diff --git a/.gitmodules b/.gitmodules index 47384525b2..c27f2e787f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,7 @@ [submodule "Console/Workspace"] path = Console/Workspace url = https://github.com/BEXIS2/Workspace.git + branch = . [submodule "Components/Vaiona"] path = Components/Vaiona url = https://github.com/BEXIS2/VWF.Mvc.git diff --git a/Components/AAA/BExIS.Security.Services.Tests/BExIS.Security.Services.Tests.csproj b/Components/AAA/BExIS.Security.Services.Tests/BExIS.Security.Services.Tests.csproj index f50b3ed54c..de1e14e639 100644 --- a/Components/AAA/BExIS.Security.Services.Tests/BExIS.Security.Services.Tests.csproj +++ b/Components/AAA/BExIS.Security.Services.Tests/BExIS.Security.Services.Tests.csproj @@ -53,9 +53,6 @@ ..\..\..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll - - ..\..\..\packages\FluentAssertions.5.10.3\lib\net47\FluentAssertions.dll - ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll @@ -91,7 +88,7 @@ ..\..\..\packages\Moq.4.8.1\lib\net45\Moq.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\NHibernate.5.4.9\lib\net48\NHibernate.dll diff --git a/Components/AAA/BExIS.Security.Services.Tests/Subjects/GroupManagerTests.cs b/Components/AAA/BExIS.Security.Services.Tests/Subjects/GroupManagerTests.cs index c83e5f7309..e49379b316 100644 --- a/Components/AAA/BExIS.Security.Services.Tests/Subjects/GroupManagerTests.cs +++ b/Components/AAA/BExIS.Security.Services.Tests/Subjects/GroupManagerTests.cs @@ -6,6 +6,10 @@ namespace BExIS.Security.Services.Tests.Subjects [TestFixture] public class GroupManagerTests { + private readonly GroupManager _groupManager; + + + [OneTimeSetUp] public void OneTimeSetUp() { @@ -28,15 +32,11 @@ public void OneTimeTearDown() public void CreateAsync_GroupIsNull_ReturnZero() { - //Arrange - using (var a = new GroupManager()) - { - //Act - var result = a.CreateAsync(null); - - //Assert - Assert.That(result, Is.EqualTo(0)); - } + //Act + var result = _groupManager.CreateAsync(null); + + //Assert + Assert.That(result, Is.EqualTo(0)); } } } \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services.Tests/packages.config b/Components/AAA/BExIS.Security.Services.Tests/packages.config index 6557bdb2ca..af075575bb 100644 --- a/Components/AAA/BExIS.Security.Services.Tests/packages.config +++ b/Components/AAA/BExIS.Security.Services.Tests/packages.config @@ -2,7 +2,6 @@ - @@ -14,7 +13,7 @@ - + diff --git a/Components/AAA/BExIS.Security.Services/Authentication/LdapAuthenticationManager.cs b/Components/AAA/BExIS.Security.Services/Authentication/LdapAuthenticationManager.cs index a49300b7b2..426f413e10 100644 --- a/Components/AAA/BExIS.Security.Services/Authentication/LdapAuthenticationManager.cs +++ b/Components/AAA/BExIS.Security.Services/Authentication/LdapAuthenticationManager.cs @@ -10,28 +10,10 @@ namespace BExIS.Security.Services.Authentication { - public class LdapAuthenticationManager : IDisposable + public class LdapAuthenticationManager { - private readonly IUnitOfWork _guow; - private bool _isDisposed; - private readonly List _ldapConfigurations; - public LdapAuthenticationManager() - { - _guow = this.GetIsolatedUnitOfWork(); - _ldapConfigurations = GeneralSettings.LdapConfigurations; - } - - ~LdapAuthenticationManager() - { - Dispose(true); - } - - public void Dispose() - { - Dispose(true); - } public User GetUser(string name, string username, string password) { @@ -88,18 +70,5 @@ public SignInStatus ValidateUser(string name, string username, string password) return SignInStatus.Failure; } - - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - if (_guow != null) - _guow.Dispose(); - _isDisposed = true; - } - } - } } } \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services/Authentication/SignInManager.cs b/Components/AAA/BExIS.Security.Services/Authentication/SignInManager.cs index 629517b812..07901f28d3 100644 --- a/Components/AAA/BExIS.Security.Services/Authentication/SignInManager.cs +++ b/Components/AAA/BExIS.Security.Services/Authentication/SignInManager.cs @@ -1,16 +1,27 @@ using BExIS.Security.Entities.Subjects; using BExIS.Security.Services.Subjects; using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; using Microsoft.Owin.Security; +using Org.BouncyCastle.Crypto; +using Vaiona.IoC; namespace BExIS.Security.Services.Authentication { - public sealed class SignInManager : SignInManager + public class SignInManager : SignInManager { - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Objekte verwerfen, bevor Bereich verloren geht", Justification = "")] - public SignInManager(IAuthenticationManager authenticationManager, UserManager userManager) - : base(new IdentityUserService(userManager), authenticationManager) + // Konstruktor bleibt gleich + public SignInManager( + UserManager userManager, + IAuthenticationManager authenticationManager) + : base(userManager, authenticationManager) + { } + + public static SignInManager Create(IdentityFactoryOptions options, IOwinContext context) { + var userManager = IoCFactory.Container.Resolve(); // ← aus Unity! + var authManager = context.Authentication; + return new SignInManager(userManager, authManager); } } } \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services/Authorization/EntityPermissionManager.cs b/Components/AAA/BExIS.Security.Services/Authorization/EntityPermissionManager.cs index 9db1b8b91e..3fcdd8440c 100644 --- a/Components/AAA/BExIS.Security.Services/Authorization/EntityPermissionManager.cs +++ b/Components/AAA/BExIS.Security.Services/Authorization/EntityPermissionManager.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; +using System.Linq.Expressions; using System.Threading.Tasks; using Vaiona.Persistence.Api; using Vaiona.Utils.Cfg; @@ -15,30 +16,42 @@ namespace BExIS.Security.Services.Authorization { - public class EntityPermissionManager : IDisposable + public class EntityPermissionManager { - private readonly IUnitOfWork _guow; - private bool _isDisposed; - - public EntityPermissionManager() + public int Count() { - _guow = this.GetIsolatedUnitOfWork(); - EntityPermissionRepository = _guow.GetReadOnlyRepository(); + using (var uow = this.GetUnitOfWork()) + { + var entityPermissionRepository = uow.GetReadOnlyRepository(); + return entityPermissionRepository.Query().Count(); + } } - ~EntityPermissionManager() + public int Count(Expression> predicate) { - Dispose(true); + using (var uow = this.GetUnitOfWork()) + { + var entityPermissionRepository = uow.GetReadOnlyRepository(); + return entityPermissionRepository.Query(predicate).Count(); + } } - public IReadOnlyRepository EntityPermissionRepository { get; } - public IQueryable EntityPermissions => EntityPermissionRepository.Query(); + public IList Get() + { + using (var uow = this.GetUnitOfWork()) + { + var entityPermissionRepository = uow.GetReadOnlyRepository(); + + var entityPermissions = entityPermissionRepository.Get(); + return entityPermissions; + } + } public async Task CreateAsync(EntityPermission entityPermission) { using (var uow = this.GetUnitOfWork()) { - var entityPermissionRepository = _guow.GetRepository(); + var entityPermissionRepository = uow.GetRepository(); var result = entityPermissionRepository.Put(entityPermission); uow.Commit(); @@ -175,11 +188,6 @@ public async Task DeleteAsync(long entityPermissionId) } } - public void Dispose() - { - Dispose(true); - } - public async Task ExistsAsync(long entityId, long key) { using (var uow = this.GetUnitOfWork()) @@ -232,6 +240,16 @@ public async Task ExistsAsync(Subject subject, Entity entity, long key) } } + public IList Find(Expression> predicate) + { + using (var uow = this.GetUnitOfWork()) + { + var entityPermissionRepository = uow.GetReadOnlyRepository(); + var entityPermissions = entityPermissionRepository.Query(predicate).ToList(); + return entityPermissions; + } + } + public async Task FindAsync(long entityId, long instanceId) { using (var uow = this.GetUnitOfWork()) @@ -578,12 +596,5 @@ public async Task UpdateAsync(EntityPermission entity) await Task.CompletedTask; } - - protected void Dispose(bool disposing) - { - if (_isDisposed || !disposing) return; - _guow?.Dispose(); - _isDisposed = true; - } } } diff --git a/Components/AAA/BExIS.Security.Services/Authorization/FeaturePermissionManager.cs b/Components/AAA/BExIS.Security.Services/Authorization/FeaturePermissionManager.cs index 6e6aa0547b..6975cb28db 100644 --- a/Components/AAA/BExIS.Security.Services/Authorization/FeaturePermissionManager.cs +++ b/Components/AAA/BExIS.Security.Services/Authorization/FeaturePermissionManager.cs @@ -266,7 +266,7 @@ public async Task HasAccessAsync(string subjectName, string module, str if (operation == null) return false; var feature = operation?.Feature; - var subject = SubjectRepository.Query(s => s.Name.ToUpperInvariant() == subjectName.ToUpperInvariant() && s is T).FirstOrDefault(); + var subject = !string.IsNullOrEmpty(subjectName) ? SubjectRepository.Query(s => s.Name.ToUpperInvariant() == subjectName.ToUpperInvariant() && s is T).FirstOrDefault() : null; //both exits if (feature != null) diff --git a/Components/AAA/BExIS.Security.Services/BExIS.Security.Services.csproj b/Components/AAA/BExIS.Security.Services/BExIS.Security.Services.csproj index 892604ef06..f99f165685 100644 --- a/Components/AAA/BExIS.Security.Services/BExIS.Security.Services.csproj +++ b/Components/AAA/BExIS.Security.Services/BExIS.Security.Services.csproj @@ -52,12 +52,18 @@ prompt + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + ..\..\..\packages\Portable.BouncyCastle.1.9.0\lib\net40\BouncyCastle.Crypto.dll ..\..\..\packages\BouncyCastle.Cryptography.2.4.0\lib\net461\BouncyCastle.Cryptography.dll + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + ..\..\..\packages\MailKit.3.1.1\lib\net48\MailKit.dll @@ -67,6 +73,7 @@ ..\..\..\packages\Microsoft.AspNet.Identity.Owin.2.2.4\lib\net45\Microsoft.AspNet.Identity.Owin.dll + ..\..\..\packages\Microsoft.IdentityModel.JsonWebTokens.5.7.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll @@ -104,7 +111,10 @@ ..\..\..\packages\MimeKit.4.8.0\lib\net48\MimeKit.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll + + + ..\..\..\packages\NHibernate.5.4.9\lib\net48\NHibernate.dll ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll @@ -112,6 +122,12 @@ ..\..\..\packages\Owin.Security.Providers.Orcid.2.26.0\lib\net45\Owin.Security.Providers.Orcid.dll + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll + ..\..\..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll @@ -138,9 +154,12 @@ ..\..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + ..\..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + ..\..\Vaiona\Vaiona.Entities\bin\Release\Vaiona.Entities.dll @@ -166,11 +185,11 @@ - - + + - + @@ -194,6 +213,10 @@ {0815d220-3625-4e23-bbbc-8152345637fe} Vaiona.Entities + + {29A7BE0F-A17C-4AE8-8CA1-15FE4DD74129} + Vaiona.IoC + {640bf81d-354a-4bf0-85fc-f0ad587cf8a2} Vaiona.Persistence.Api diff --git a/Components/AAA/BExIS.Security.Services/Subjects/GroupManager.cs b/Components/AAA/BExIS.Security.Services/Subjects/GroupManager.cs index b0e54be92f..a11abb74b3 100644 --- a/Components/AAA/BExIS.Security.Services/Subjects/GroupManager.cs +++ b/Components/AAA/BExIS.Security.Services/Subjects/GroupManager.cs @@ -1,214 +1,221 @@ using BExIS.Security.Entities.Authorization; using BExIS.Security.Entities.Subjects; +using BExIS.Security.Services.Authorization; +using BExIS.Security.Services.FormerMember; using BExIS.Utils.NH.Querying; using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; +using System.Linq.Expressions; using System.Threading.Tasks; using Vaiona.Persistence.Api; namespace BExIS.Security.Services.Subjects { - public class GroupManager : IQueryableRoleStore + public class GroupManager : RoleManager { - private readonly IUnitOfWork _guow; - private bool _isDisposed; - - public GroupManager() + public GroupManager(IRoleStore store) : base(store) { - _guow = this.GetIsolatedUnitOfWork(); - GroupRepository = _guow.GetReadOnlyRepository(); } - ~GroupManager() + public async Task CreateGroupAsync(string name) { - Dispose(true); - } + if (string.IsNullOrWhiteSpace(name)) + return IdentityResult.Failed("Group name is required."); - public IQueryable Groups => GroupRepository.Query(); - public IQueryable Roles => GroupRepository.Query(); - private IReadOnlyRepository GroupRepository { get; } - - /// - /// returns subset of groups based on the parameters - /// and also count of filtered list - /// - /// - /// - /// - /// - /// - /// - public List GetGroups(FilterExpression filter, OrderByExpression orderBy, int pageNumber, int pageSize, out int count) - { - var orderbyClause = orderBy?.ToLINQ(); - var whereClause = filter?.ToLINQ(); - count = 0; - try - { - using (IUnitOfWork uow = this.GetUnitOfWork()) - { - if (whereClause != null && orderBy != null) - { - var l = Groups.Where(whereClause); - var x = l.OrderBy(orderbyClause); - var y = x.Skip((pageNumber - 1) * pageSize); - var z = y.Take(pageSize); + if (await RoleExistsAsync(name)) + return IdentityResult.Failed("Group already exists."); - count = l.Count(); + var group = new Group { Name = name }; + return await CreateAsync(group); + } - return z.ToList(); - } - else if (whereClause != null) - { - var filtered = Groups.Where(whereClause); - count = filtered.Count(); + public Task GetByIdAsync(long id) + => FindByIdAsync(id); - return filtered.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); - } + public Task GetByNameAsync(string name) + => FindByNameAsync(name); - if (orderBy != null) - { - count = Groups.Count(); - return Groups.OrderBy(orderbyClause).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); - } + public Task GroupExistsAsync(string name) + => RoleExistsAsync(name); - count = count = Groups.Count(); - - // without filter and order - return Groups.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); - } - } - catch (Exception ex) - { - throw new Exception(string.Format("Could not retrieve filtered groups."), ex); - } - } - - public Task CreateAsync(Group role) + public async Task RenameGroupAsync(long id, string newName) { - if (role == null) - //return Task.FromException(new Exception()); - return Task.CompletedTask; + if (string.IsNullOrWhiteSpace(newName)) + return IdentityResult.Failed("Name required."); - if (string.IsNullOrEmpty(role.Name)) - //return Task.FromException(new Exception()); - return Task.CompletedTask; - - if (FindByNameAsync(role.Name)?.Result != null) - //return Task.FromException(new Exception()); - return Task.CompletedTask; - - var groupRepository = _guow.GetRepository(); - groupRepository.Put(role); - _guow.Commit(); + var group = await FindByIdAsync(id); + if (group == null) + return IdentityResult.Failed("Group not found."); - return Task.CompletedTask; + group.Name = newName; + return await UpdateAsync(group); } - public Task DeleteAsync(Group role) + public async Task DeleteGroupAsync(long id) { - var groupRepository = _guow.GetRepository(); - groupRepository.Delete(role); - _guow.Commit(); + var group = await FindByIdAsync(id); + if (group == null) + return IdentityResult.Failed("Group not found."); - return Task.CompletedTask; + return await DeleteAsync(group); } - public Task DeleteByIdAsync(long roleId) + public Group Create(Group group) { - var groupRepository = _guow.GetRepository(); - var group = groupRepository.Get(roleId); + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetRepository(); + groupRepository.Put(group); + uow.Commit(); + return group; + } + } + public bool Delete(Group group) + { if (group == null) - //return Task.FromException(new Exception()); - return Task.FromResult(false); + return false; + return Delete(group.Id); + } - // Users - var userRepository = _guow.GetRepository(); - foreach (var user in group.Users) + public bool Delete(long id) + { + using (var uow = this.GetUnitOfWork()) { - user.Groups.Remove(group); - userRepository.Put(user); + var groupRepository = uow.GetRepository(); + var group = groupRepository.Get(id); + if (group != null) + { + groupRepository.Delete(group); + uow.Commit(); + return true; + } + return false; } + } - // EntityPermissions - var entityPermissionRepository = _guow.GetRepository(); - foreach (var entityPermission in entityPermissionRepository.Get(e => e.Subject.Id == roleId)) + public int Count(Expression> predicate) + { + using (var uow = this.GetUnitOfWork()) { - entityPermissionRepository.Delete(entityPermission); + var groupRepository = uow.GetReadOnlyRepository(); + return groupRepository.Query(predicate).Count(); } + } - // FeaturePermissions - var featurePermissionRepository = _guow.GetRepository(); - foreach (var featurePermission in featurePermissionRepository.Get(e => e.Subject.Id == roleId)) + public int Count() + { + using (var uow = this.GetUnitOfWork()) { - featurePermissionRepository.Delete(featurePermission); + var groupRepository = uow.GetReadOnlyRepository(); + return groupRepository.Query().Count(); } - - var result = groupRepository.Delete(group); - - _guow.Commit(); - - return Task.FromResult(result); } - public void Dispose() + public Group Get(long id) { - this.Dispose(true); + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetReadOnlyRepository(); + + var group = groupRepository.Get(id); + return group; + } } - public Task FindByIdAsync(long roleId) + public Group Get(string groupName) { - return Task.FromResult(GroupRepository.Get(roleId)); + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetReadOnlyRepository(); + + return groupRepository.Query(r => r.Name == groupName).SingleOrDefault(); + } } - public Task FindByNameAsync(string roleName) + public IList Get() { - var groups = GroupRepository.Query(u => u.Name.ToLowerInvariant() == roleName.ToLowerInvariant()).ToList(); + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetReadOnlyRepository(); - if (!groups.Any()) - return Task.FromResult(null); + var groups = groupRepository.Get(); + return groups; + } + } - if (groups.Count > 1) - return Task.FromResult(null); + public IList Find(Expression> predicate) + { + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetReadOnlyRepository(); + var groups = groupRepository.Query(predicate).ToList(); + return groups; + } + } - return Task.FromResult(groups.Single()); + public IList Find() + { + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetReadOnlyRepository(); + var groups = groupRepository.Query().ToList(); + return groups; + } } - public Task UpdateAsync(Group role) + public IList Find(FilterExpression filter, OrderByExpression orderBy, int pageNumber, int pageSize, out int count) { - if (role == null) - return Task.CompletedTask; + var orderbyClause = orderBy?.ToLINQ(); + var whereClause = filter?.ToLINQ(); + count = 0; + try + { + using (IUnitOfWork uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetReadOnlyRepository(); + IQueryable groups = groupRepository.Query(); + if (whereClause != null && orderBy != null) + { + var l = groups.Where(whereClause); + var x = l.OrderBy(orderbyClause); + var y = x.Skip((pageNumber - 1) * pageSize); + var z = y.Take(pageSize); - if (string.IsNullOrEmpty(role.Name)) - return Task.CompletedTask; + count = l.Count(); - if (FindByIdAsync(role.Id)?.Result == null) - return Task.CompletedTask; + return z.ToList(); + } + else if (whereClause != null) + { + var filtered = groups.Where(whereClause); + count = filtered.Count(); + + return filtered.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); + } - _guow.GetRepository().Merge(role); - var merged = _guow.GetRepository().Get(role.Id); - _guow.GetRepository().Put(merged); - _guow.Commit(); + if (orderBy != null) + { + count = groups.Count(); + return groups.OrderBy(orderbyClause).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); + } - return Task.CompletedTask; - } + count = count = groups.Count(); - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - if (_guow != null) - _guow.Dispose(); - _isDisposed = true; + // without filter and order + return groups.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); } } + catch (Exception ex) + { + throw new Exception(string.Format("Could not retrieve filtered groups."), ex); + } } } } \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services/Subjects/GroupStore.cs b/Components/AAA/BExIS.Security.Services/Subjects/GroupStore.cs new file mode 100644 index 0000000000..fcb62c081a --- /dev/null +++ b/Components/AAA/BExIS.Security.Services/Subjects/GroupStore.cs @@ -0,0 +1,94 @@ +using BExIS.Security.Entities.Authorization; +using BExIS.Security.Entities.Subjects; +using BExIS.Security.Entities.Versions; +using BExIS.Utils.NH.Querying; +using Microsoft.AspNet.Identity; +using NHibernate; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading.Tasks; +using Vaiona.Persistence.Api; + +namespace BExIS.Security.Services.Subjects +{ + public class GroupStore : IQueryableRoleStore, IDisposable + { + public IQueryable Roles + { + get + { + using (var uow = this.GetUnitOfWork()) + { + return uow.GetReadOnlyRepository().Query().ToList().AsQueryable(); + } + } + } + + public Task CreateAsync(Group role) + { + if (role == null) + throw new ArgumentNullException(nameof(role)); + + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetRepository(); + + groupRepository.Put(role); + uow.Commit(); + + return Task.CompletedTask; + } + } + + public Task DeleteAsync(Group role) + { + using (var uow = this.GetUnitOfWork()) + { + uow.GetRepository().Delete(role); + uow.Commit(); + + return Task.CompletedTask; + } + } + + public Task UpdateAsync(Group role) + { + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetRepository(); + + groupRepository.Merge(role); + uow.Commit(); + + return Task.CompletedTask; + } + + } + + public Task FindByIdAsync(long id) + { + using (var uow = this.GetUnitOfWork()) + { + return Task.FromResult(uow.GetReadOnlyRepository().Get(id)); + } + } + + public Task FindByNameAsync(string name) + { + using (var uow = this.GetUnitOfWork()) + { + return Task.FromResult( + uow.GetReadOnlyRepository() + .Query(g => g.Name == name).SingleOrDefault() + ); + } + } + + public void Dispose() + { + + } + } +} diff --git a/Components/AAA/BExIS.Security.Services/Subjects/IdentityGroupService.cs b/Components/AAA/BExIS.Security.Services/Subjects/IdentityGroupService.cs deleted file mode 100644 index ba82b2220e..0000000000 --- a/Components/AAA/BExIS.Security.Services/Subjects/IdentityGroupService.cs +++ /dev/null @@ -1,49 +0,0 @@ -using BExIS.Security.Entities.Subjects; -using BExIS.Utils.NH.Querying; -using Microsoft.AspNet.Identity; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace BExIS.Security.Services.Subjects -{ - public class IdentityGroupService : RoleManager - { - private readonly GroupManager _groupManager; - private bool _disposed; - - //[System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Objekte verwerfen, bevor Bereich verloren geht", Justification = "")] - public IdentityGroupService(GroupManager groupManager) : base(groupManager) - { - _groupManager = groupManager ?? throw new ArgumentNullException(nameof(groupManager)); - - RoleValidator = new RoleValidator(this) - { - }; - } - - public Task DeleteByIdAsync(long roleId) - { - return _groupManager.DeleteByIdAsync(roleId); - } - - public List GetGroups(FilterExpression filter, OrderByExpression orderBy, int pageNumber, int pageSize, out int count) - { - return _groupManager.GetGroups(filter, orderBy, pageNumber, pageSize, out count); - } - protected override void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - _groupManager?.Dispose(); - } - - _disposed = true; - } - - base.Dispose(disposing); - } - } -} \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services/Subjects/IdentityUserService.cs b/Components/AAA/BExIS.Security.Services/Subjects/IdentityUserService.cs deleted file mode 100644 index f3e5d73b29..0000000000 --- a/Components/AAA/BExIS.Security.Services/Subjects/IdentityUserService.cs +++ /dev/null @@ -1,75 +0,0 @@ -using BExIS.Security.Entities.Subjects; -using BExIS.Security.Services.Utilities; -using Microsoft.AspNet.Identity; -using Microsoft.AspNet.Identity.Owin; -using System; -using System.Threading.Tasks; - -namespace BExIS.Security.Services.Subjects -{ - public class IdentityUserService : UserManager - { - private readonly UserManager _userManager; - private bool _disposed; - - //[System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Objekte verwerfen, bevor Bereich verloren geht", Justification = "")] - public IdentityUserService(UserManager userManager) : base(userManager) - { - _userManager = userManager; - - // Configure validation logic for usernames - UserValidator = new UserValidator(this) - { - AllowOnlyAlphanumericUserNames = false, - RequireUniqueEmail = true - }; - - // Configure validation logic for passwords - PasswordValidator = new PasswordValidator - { - RequiredLength = 6, - RequireNonLetterOrDigit = false, - RequireDigit = false, - RequireLowercase = false, - RequireUppercase = false, - }; - - // Configure user lockout defaults - UserLockoutEnabledByDefault = true; - DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); - MaxFailedAccessAttemptsBeforeLockout = 5; - - // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user - // You can write your own provider and plug it in here. - EmailService = new EmailService(); - - var dataProtectionProvider = Auth.DataProtectionProvider; - - if (dataProtectionProvider == null) return; - - var dataProtector = dataProtectionProvider.Create("ASP.NET Identity"); - UserTokenProvider = new DataProtectorTokenProvider(dataProtector); - } - - [Obsolete("Dot not use it, and there is no other way of changing phone numbers!", true)] // this is an example of making a base class method obsolete and causing compilation error - public new Task ChangePhoneNumberAsync(long userId, string phoneNumber, string token) - { - return base.ChangePhoneNumberAsync(userId, phoneNumber, token); - } - - protected override void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - _userManager?.Dispose(); - } - - _disposed = true; - } - - base.Dispose(disposing); - } - } -} \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services/Subjects/UserManager.cs b/Components/AAA/BExIS.Security.Services/Subjects/UserManager.cs index 43b7330ae3..88c97dca09 100644 --- a/Components/AAA/BExIS.Security.Services/Subjects/UserManager.cs +++ b/Components/AAA/BExIS.Security.Services/Subjects/UserManager.cs @@ -1,8 +1,12 @@ -using BExIS.Security.Entities.Authentication; -using BExIS.Security.Entities.Authorization; -using BExIS.Security.Entities.Subjects; +using BExIS.Security.Entities.Subjects; +using BExIS.Security.Services.Authentication; +using BExIS.Security.Services.Utilities; +using BExIS.Utils.Config; +using BExIS.Utils.Config.Configurations; using BExIS.Utils.NH.Querying; using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; using System; using System.Collections.Generic; using System.Linq; @@ -12,482 +16,115 @@ namespace BExIS.Security.Services.Subjects { - public class UserManager : IUserEmailStore, IUserLoginStore, IUserPasswordStore, IUserLockoutStore, IUserRoleStore, IUserTwoFactorStore, IUserSecurityStampStore, IQueryableUserStore + public class UserManager : UserManager { - private readonly IUnitOfWork _guow; - private bool _isDisposed; - - public UserManager() - { - _guow = this.GetIsolatedUnitOfWork(); - UserRepository = _guow.GetReadOnlyRepository(); - LoginRepository = _guow.GetReadOnlyRepository(); - GroupRepository = _guow.GetReadOnlyRepository(); - } - - ~UserManager() + private SecurityConfiguration _securityConfiguration; + public UserManager(IUserStore store): base(store) { - Dispose(true); - } - - public IQueryable Users => UserRepository.Query(); - - public IQueryable Logins => LoginRepository.Query(); + _securityConfiguration = GeneralSettings.SecurityConfiguration; - public IQueryable Groups => GroupRepository.Query(); + var userValidatorConfiguration = _securityConfiguration?.UserValidatorConfiguration; - private IReadOnlyRepository UserRepository { get; } - - private IReadOnlyRepository GroupRepository { get; } - - private IReadOnlyRepository LoginRepository { get; } - - public List GetUsers(FilterExpression filter, OrderByExpression orderBy, int pageNumber, int pageSize, out int count) - { - var orderbyClause = orderBy?.ToLINQ(); - var whereClause = filter?.ToLINQ(); - - count = 0; - - try + // Configure validation logic for usernames + UserValidator = new UserValidator(this) { - if (whereClause != null && orderBy != null) - { - var l = Users.Where(whereClause); - var x = l.OrderBy(orderbyClause); - var y = x.Skip((pageNumber - 1) * pageSize); - var z = y.Take(pageSize); - - count = l.Count(); + AllowOnlyAlphanumericUserNames = userValidatorConfiguration?.AllowOnlyAlphanumericUserNames ?? false, + RequireUniqueEmail = userValidatorConfiguration?.RequireUniqueEmail ?? true + }; - return z.ToList(); - } - else if (whereClause != null) - { - var filtered = Users.Where(whereClause); - count = filtered.Count(); + var passwordValidatorConfiguration = _securityConfiguration?.PasswordValidatorConfiguration; - return filtered.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); - } - if (orderBy != null) - { - count = Users.Count(); - return Users.OrderBy(orderbyClause).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); - } - - count = Users.Count(); - - return Users.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); - } - catch (Exception ex) + // Configure validation logic for passwords + PasswordValidator = new PasswordValidator { - throw new Exception(string.Format("Could not retrieve filtered users."), ex); - } - } - - #region IUserEmailStore + RequiredLength = passwordValidatorConfiguration?.RequiredLength ?? 6, + RequireNonLetterOrDigit = passwordValidatorConfiguration?.RequireNonLetterOrDigit ?? false, + RequireDigit = passwordValidatorConfiguration?.RequireDigit?? false, + RequireLowercase = passwordValidatorConfiguration?.RequireLowercase ?? false, + RequireUppercase = passwordValidatorConfiguration?.RequireUppercase ?? false + }; - public Task CreateAsync(User user) - { - if (user == null) - //return Task.FromException(new Exception()); - return Task.CompletedTask; + // Configure user lockout defaults + UserLockoutEnabledByDefault = true; + DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); + MaxFailedAccessAttemptsBeforeLockout = 5; - if (string.IsNullOrEmpty(user.UserName)) - //return Task.FromException(new Exception()); - return Task.CompletedTask; + // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user + // You can write your own provider and plug it in here. + EmailService = new EmailService(); - if (FindByNameAsync(user.UserName)?.Result != null) - //return Task.FromException(new Exception()); - return Task.CompletedTask; + var dataProtectionProvider = Auth.DataProtectionProvider; - var userRepository = _guow.GetRepository().Put(user); - _guow.Commit(); + if (dataProtectionProvider == null) return; - return Task.CompletedTask; + var dataProtector = dataProtectionProvider.Create("ASP.NET Identity"); + UserTokenProvider = new DataProtectorTokenProvider(dataProtector); } - public Task DeleteAsync(User user) + [Obsolete("Dot not use it, and there is no other way of changing phone numbers!", true)] // this is an example of making a base class method obsolete and causing compilation error + public new Task ChangePhoneNumberAsync(long userId, string phoneNumber, string token) { - _guow.GetRepository().Delete(user.Id); - _guow.Commit(); - - return Task.CompletedTask; + return base.ChangePhoneNumberAsync(userId, phoneNumber, token); } - public Task DeleteByIdAsync(long userId) + public User Create(User user) { - var userRepository = _guow.GetRepository(); - var user = userRepository.Get(userId); - - if(user == null) - //return Task.FromException(new Exception()); - return Task.FromResult(false); - - // Logins - var loginsRepository = _guow.GetRepository(); - foreach (var login in loginsRepository.Get(l => l.User.Id == userId)) + using (var uow = this.GetUnitOfWork()) { - loginsRepository.Delete(login); + var userRepository = uow.GetRepository(); + userRepository.Put(user); + uow.Commit(); + return user; } - - // EntityPermissions - var entityPermissionRepository = _guow.GetRepository(); - foreach (var entityPermission in entityPermissionRepository.Get(e => e.Subject.Id == userId)) - { - entityPermissionRepository.Delete(entityPermission); - } - - // FeaturePermissions - var featurePermissionRepository = _guow.GetRepository(); - foreach (var featurePermission in featurePermissionRepository.Get(e => e.Subject.Id == userId)) - { - featurePermissionRepository.Delete(featurePermission); - } - - var result = userRepository.Delete(user); - - _guow.Commit(); - - return Task.FromResult(result); - } - - public void Dispose() - { - Dispose(true); } - public Task FindByEmailAsync(string email) + public IList Find(FilterExpression filter, OrderByExpression orderBy, int pageNumber, int pageSize, out int count) { - var users = UserRepository.Query(u => u.Email.ToLowerInvariant() == email.ToLowerInvariant()).ToList(); - - if (!users.Any()) - //return Task.FromException(new Exception()); - return Task.FromResult(null); - - if (users.Count > 1) - //return Task.FromException(new Exception()); - return Task.FromResult(null); - - return Task.FromResult(users.Single()); - } - - public Task FindByIdAsync(long userId) - { - return Task.FromResult(UserRepository.Get(userId)); - } - - public Task FindByNameAsync(string userName) - { - var users = UserRepository.Query().Where(u => u.Name.ToLowerInvariant() == userName.ToLowerInvariant()).ToList(); - - if (!users.Any()) - //return Task.FromException(new Exception()); - return Task.FromResult(null); - - if (users.Count > 1) - //return Task.FromException(new Exception()); - return Task.FromResult(null); - - return Task.FromResult(users.Single()); - } - - public Task GetEmailAsync(User user) - { - return Task.FromResult(user.Email); - } - - public Task GetEmailConfirmedAsync(User user) - { - return Task.FromResult(user.IsEmailConfirmed); - } - - public Task SetEmailAsync(User user, string email) - { - user.Email = email; - return Task.CompletedTask; - } - - public Task SetEmailConfirmedAsync(User user, bool confirmed) - { - user.IsEmailConfirmed = confirmed; - return Task.CompletedTask; - } - - public Task UpdateAsync(User user) - { - if (user == null) - //return Task.FromException(new Exception()); - return Task.CompletedTask; - - if (string.IsNullOrEmpty(user.UserName)) - //return Task.FromException(new Exception()); - return Task.CompletedTask; - - if (FindByIdAsync(user.Id)?.Result == null) - //return Task.FromException(new Exception()); - return Task.CompletedTask; - - _guow.GetRepository().Merge(user); - var merged = _guow.GetRepository().Get(user.Id); - _guow.GetRepository().Put(merged); - _guow.Commit(); - - return Task.CompletedTask; - } - - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) + var orderbyClause = orderBy?.ToLINQ(); + var whereClause = filter?.ToLINQ(); + count = 0; + try { - if (disposing) + using (IUnitOfWork uow = this.GetUnitOfWork()) { - if (_guow != null) - _guow.Dispose(); - _isDisposed = true; + var userRepository = uow.GetReadOnlyRepository(); + IQueryable users = userRepository.Query(); + if (whereClause != null && orderBy != null) + { + var l = users.Where(whereClause); + var x = l.OrderBy(orderbyClause); + var y = x.Skip((pageNumber - 1) * pageSize); + var z = y.Take(pageSize); + + count = l.Count(); + + return z.ToList(); + } + else if (whereClause != null) + { + var filtered = users.Where(whereClause); + count = filtered.Count(); + + return filtered.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); + } + + if (orderBy != null) + { + count = users.Count(); + return users.OrderBy(orderbyClause).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); + } + + count = count = users.Count(); + + // without filter and order + return users.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); } } - } - - #endregion IUserEmailStore - - #region IUserLoginStore - - public Task AddLoginAsync(User user, UserLoginInfo login) - { - var loginRepository = _guow.GetRepository(); - - user = UserRepository.Get(user.Id); - var userLogin = new Login() - { - ProviderKey = login.ProviderKey, - LoginProvider = login.LoginProvider, - User = user - }; - - loginRepository.Put(userLogin); - _guow.Commit(); - - return Task.CompletedTask; - } - - public Task FindAsync(UserLoginInfo login) - { - var users = LoginRepository.Query(m => m.LoginProvider.ToLowerInvariant() == login.LoginProvider.ToLowerInvariant() && m.ProviderKey.ToLowerInvariant() == login.ProviderKey.ToLowerInvariant()).Select(m => m.User).ToList(); - - if (!users.Any()) - //return Task.FromException(new Exception()); - return Task.FromResult(null); - - if (users.Count > 1) - //return Task.FromException(new Exception()); - return Task.FromResult(null); - - return Task.FromResult(users.Single()); - } - - public Task> GetLoginsAsync(User user) - { - return Task.FromResult>((user.Logins).Select(login => new UserLoginInfo(login.LoginProvider, login.ProviderKey)).ToList()); - } - - public Task RemoveLoginAsync(User user, UserLoginInfo login) - { - var userRepository = _guow.GetRepository(); - - user = userRepository.Get(user.Id); - var info = user.Logins.SingleOrDefault(x => x.LoginProvider == login.LoginProvider && x.ProviderKey == login.ProviderKey); - if (info == null) return Task.FromResult(0); - - user.Logins.Remove(info); - userRepository.Put(user); - _guow.Commit(); - - return Task.CompletedTask; - } - - #endregion IUserLoginStore - - #region IUserPasswordStore - - public Task GetPasswordHashAsync(User user) - { - return Task.FromResult(user.Password); - } - - public Task HasPasswordAsync(User user) - { - return Task.FromResult(user.Password != null); - } - - public Task SetPasswordHashAsync(User user, string passwordHash) - { - user.Password = passwordHash; - return Task.CompletedTask; - } - - #endregion IUserPasswordStore - - #region IUserLockoutStore - - public Task GetAccessFailedCountAsync(User user) - { - return Task.FromResult(user.AccessFailedCount); - } - - public Task GetLockoutEnabledAsync(User user) - { - return Task.FromResult(user.LockoutEnabled); - } - - public Task GetLockoutEndDateAsync(User user) - { - DateTimeOffset dateTimeOffset; - - if (user.LockoutEndDate.HasValue) - { - var lockoutEndDate = user.LockoutEndDate; - dateTimeOffset = new DateTimeOffset(DateTime.SpecifyKind(lockoutEndDate.Value, DateTimeKind.Utc)); - } - else + catch (Exception ex) { - dateTimeOffset = new DateTimeOffset(); + throw new Exception(string.Format("Could not retrieve filtered groups."), ex); } - return Task.FromResult(dateTimeOffset); throw new NotImplementedException(); - } - - public Task IncrementAccessFailedCountAsync(User user) - { - user.AccessFailedCount = user.AccessFailedCount + 1; - return Task.FromResult(user.AccessFailedCount); - } - - public Task ResetAccessFailedCountAsync(User user) - { - user.AccessFailedCount = 0; - return Task.CompletedTask; - } - - public Task SetLockoutEnabledAsync(User user, bool enabled) - { - user.LockoutEnabled = enabled; - return Task.CompletedTask; } - - public Task SetLockoutEndDateAsync(User user, DateTimeOffset lockoutEnd) - { - user.LockoutEndDate = lockoutEnd.UtcDateTime; ; - return Task.CompletedTask; - } - - #endregion IUserLockoutStore - - #region IUserRoleStore - - public Task AddToRoleAsync(User user, string roleName) - { - var groups = GroupRepository.Query(g => g.Name.ToLowerInvariant() == roleName.ToLowerInvariant()).ToList(); - - if (!groups.Any()) - //return Task.FromException(new Exception()); - return Task.FromResult(false); - - if (groups.Count > 1) - //return Task.FromException(new Exception()); - return Task.FromResult(false); - - var group = groups.Single(); - - //// [Sven][Workaround][2017/10/09] - //// It is necessary to "re-get" the object. Other than that, "Load", "Reload" or other functions are not working here. - //// In general, there is an issue with the sessions. The primary error message was - //// "reassociated object has dirty collection: BExIS.Security.Entities.Subjects.User.Groups" - //// but with "Load" or "Reload" it changed to - //// "a different object with the same identifier value was already associated with the session: 32768, of entity: BExIS.Security.Entities.Subjects.User". - //// At https://forum.hibernate.org/viewtopic.php?t=934551 is claimed to change "session.Lock()" to "session.Update" which should be done at Vaiona. - /// - - user = UserRepository.Get(user.Id); - if (user == null) return Task.FromResult(false); - - var userRepository = _guow.GetRepository(); - user.Groups.Add(group); - userRepository.Put(user); - _guow.Commit(); - - return Task.FromResult(true); - } - - public Task> GetRolesAsync(User user) - { - user = UserRepository.Get(user.Id); - - var groups = user.Groups.Select(m => m.Name).ToList(); - - return Task.FromResult((IList)groups); - } - - public Task IsInRoleAsync(User user, string roleName) - { - user = UserRepository.Get(user.Id); - - return Task.FromResult(user.Groups.Any(m => m.Name.ToLowerInvariant() == roleName.ToLowerInvariant())); - } - - public Task RemoveFromRoleAsync(User user, string roleName) - { - var group = GroupRepository.Query(g => g.Name.ToUpperInvariant() == roleName.ToUpperInvariant()).FirstOrDefault(); - - if (group == null) return Task.FromResult(false); - - user = UserRepository.Get(user.Id); - if (user == null) return Task.FromResult(false); - - var userRepository = _guow.GetRepository(); - user.Groups.Remove(group); - userRepository.Put(user); - _guow.Commit(); - - return Task.FromResult(true); - } - - #endregion IUserRoleStore - - #region IUserTwoFactorStore - - public Task GetTwoFactorEnabledAsync(User user) - { - return Task.FromResult(false); - } - - /// - /// - /// - /// - /// - /// - public Task SetTwoFactorEnabledAsync(User user, bool enabled) - { - user.IsTwoFactorEnabled = false; - return Task.CompletedTask; - } - - #endregion IUserTwoFactorStore - - #region IUserSecurityStampStore - - public Task GetSecurityStampAsync(User user) - { - return Task.FromResult(user.SecurityStamp); - } - - public Task SetSecurityStampAsync(User user, string stamp) - { - user.SecurityStamp = stamp; - return Task.CompletedTask; - } - - #endregion IUserSecurityStampStore } } \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services/Subjects/UserStore.cs b/Components/AAA/BExIS.Security.Services/Subjects/UserStore.cs new file mode 100644 index 0000000000..57f73131cf --- /dev/null +++ b/Components/AAA/BExIS.Security.Services/Subjects/UserStore.cs @@ -0,0 +1,395 @@ +using BExIS.Security.Entities.Authentication; +using BExIS.Security.Entities.Authorization; +using BExIS.Security.Entities.Subjects; +using Microsoft.AspNet.Identity; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading.Tasks; +using Vaiona.Persistence.Api; + +namespace BExIS.Security.Services.Subjects +{ + public class UserStore : IUserEmailStore, IUserLoginStore, IUserPasswordStore, IUserLockoutStore, IUserRoleStore, IUserSecurityStampStore, IUserTwoFactorStore, IQueryableUserStore, IDisposable + { + public IQueryable Users + { + get + { + var uow = this.GetUnitOfWork(); + return uow.GetReadOnlyRepository().Query(); + } + } + + #region IUserEmailStore + + public Task CreateAsync(User user) + { + if (user == null) + throw new ArgumentNullException(nameof(user)); + + if (string.IsNullOrEmpty(user.UserName)) + throw new ArgumentException("UserName required"); + + if (FindByNameAsync(user.UserName)?.Result != null) + throw new InvalidOperationException("UserName already exists"); + + using (var uow = this.GetUnitOfWork()) + { + var userRepository = uow.GetRepository(); + userRepository.Put(user); + uow.Commit(); + } + + return Task.CompletedTask; + } + + public Task DeleteAsync(User user) + { + using (var uow = this.GetUnitOfWork()) + { + uow.GetRepository().Delete(user); + uow.Commit(); + + return Task.CompletedTask; + } + } + + public Task DeleteByIdAsync(long userId) + { + using (var uow = this.GetUnitOfWork()) + { + var userRepository = uow.GetRepository(); + + var user = userRepository.Get(userId); + + if (user == null) + return Task.FromResult(false); + + // Logins + var loginsRepository = uow.GetRepository(); + foreach (var login in loginsRepository.Get(l => l.User.Id == userId)) + { + loginsRepository.Delete(login); + } + + // EntityPermissions + var entityPermissionRepository = uow.GetRepository(); + foreach (var entityPermission in entityPermissionRepository.Get(e => e.Subject.Id == userId)) + { + entityPermissionRepository.Delete(entityPermission); + } + + // FeaturePermissions + var featurePermissionRepository = uow.GetRepository(); + foreach (var featurePermission in featurePermissionRepository.Get(e => e.Subject.Id == userId)) + { + featurePermissionRepository.Delete(featurePermission); + } + + var result = userRepository.Delete(user); + uow.Commit(); + + return Task.FromResult(result); + } + } + + public void Dispose(){} + + public Task FindByEmailAsync(string email) + { + using (var uow = this.GetUnitOfWork()) + { + var userRepository = uow.GetReadOnlyRepository(); + + return Task.FromResult(userRepository.Query(u => u.Email == email).SingleOrDefault()); + } + } + + public Task FindByIdAsync(long userId) + { + using (var uow = this.GetUnitOfWork()) + { + var userRepository = uow.GetReadOnlyRepository(); + + return Task.FromResult(userRepository.Get(userId)); + } + + } + + public Task FindByNameAsync(string userName) + { + if (string.IsNullOrEmpty(userName)) + return Task.FromResult(null); + + using (var uow = this.GetUnitOfWork()) + { + var userRepository = uow.GetReadOnlyRepository(); + + return Task.FromResult(userRepository.Query(u => u.Name.ToLower() == userName.ToLower()).SingleOrDefault()); + } + } + + public Task GetEmailAsync(User user) + { + return Task.FromResult(user.Email); + } + + public Task GetEmailConfirmedAsync(User user) + { + return Task.FromResult(user.IsEmailConfirmed); + } + + public Task SetEmailAsync(User user, string email) + { + user.Email = email; + return Task.CompletedTask; + } + + public Task SetEmailConfirmedAsync(User user, bool confirmed) + { + user.IsEmailConfirmed = confirmed; + return Task.CompletedTask; + } + + public Task UpdateAsync(User user) + { + if (user == null) + return Task.FromException(new ArgumentNullException(nameof(user))); + + using (var uow = this.GetUnitOfWork()) + { + var repo = uow.GetRepository(); + repo.Merge(user); + uow.Commit(); + } + return Task.CompletedTask; + } + + #endregion IUserEmailStore + + #region IUserLoginStore + + public Task AddLoginAsync(User user, UserLoginInfo login) + { + using (var uow = this.GetUnitOfWork()) + { + var loginRepository = uow.GetRepository(); + var userRepository = uow.GetRepository(); + + var userLogin = new Login() + { + ProviderKey = login.ProviderKey, + LoginProvider = login.LoginProvider, + User = user + }; + + loginRepository.Put(userLogin); + uow.Commit(); + + return Task.CompletedTask; + + } + } + + public Task FindAsync(UserLoginInfo login) + { + using (var uow = this.GetUnitOfWork()) + { + var loginRepository = uow.GetReadOnlyRepository(); + + return Task.FromResult(loginRepository.Query(l => l.LoginProvider == login.LoginProvider && l.ProviderKey == login.ProviderKey).Select(u => u.User).SingleOrDefault()); + } + } + + public Task> GetLoginsAsync(User user) + { + return Task.FromResult>((user.Logins).Select(login => new UserLoginInfo(login.LoginProvider, login.ProviderKey)).ToList()); + } + + public Task RemoveLoginAsync(User user, UserLoginInfo login) + { + using (var uow = this.GetUnitOfWork()) + { + var userRepository = uow.GetRepository(); + user = userRepository.Get(user.Id); + var info = user.Logins.SingleOrDefault(x => x.LoginProvider == login.LoginProvider && x.ProviderKey == login.ProviderKey); + if (info == null) return Task.FromResult(0); + + user.Logins.Remove(info); + userRepository.Put(user); + uow.Commit(); + + return Task.CompletedTask; + } + } + + #endregion IUserLoginStore + + #region IUserPasswordStore + + public Task GetPasswordHashAsync(User user) + { + return Task.FromResult(user.Password); + } + + public Task HasPasswordAsync(User user) + { + return Task.FromResult(user.Password != null); + } + + public Task SetPasswordHashAsync(User user, string passwordHash) + { + user.Password = passwordHash; + return Task.CompletedTask; + } + + #endregion IUserPasswordStore + + #region IUserRoleStore + + public Task AddToRoleAsync(User user, string roleName) + { + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetReadOnlyRepository(); + var group = groupRepository.Query(g => g.Name == roleName).SingleOrDefault(); + + if (group == null) + return Task.FromException(new InvalidOperationException($"Group '{roleName}' not found.")); + + var userRepository = uow.GetRepository(); + user = userRepository.Get(user.Id); + user.Groups.Add(group); + + userRepository.Merge(user); + uow.Commit(); + + return Task.CompletedTask; + } + } + + public Task> GetRolesAsync(User user) + { + return Task.FromResult((IList)user.Groups.Select(m => m.Name).ToList()); + } + + public Task IsInRoleAsync(User user, string roleName) + { + return Task.FromResult(user.Groups.Any(m => m.Name == roleName)); + } + + public Task RemoveFromRoleAsync(User user, string roleName) + { + using (var uow = this.GetUnitOfWork()) + { + var groupRepository = uow.GetReadOnlyRepository(); + var userRepository = uow.GetRepository(); + + var group = groupRepository.Query(g => g.Name == roleName).FirstOrDefault(); + + if (group == null) return Task.FromResult(false); + + user.Groups.Remove(group); + userRepository.Put(user); + uow.Commit(); + + return Task.FromResult(true); + } + } + + #endregion IUserRoleStore + + #region IUserSecurityStampStore + + public Task GetSecurityStampAsync(User user) + { + return Task.FromResult(user.SecurityStamp); + } + + public Task SetSecurityStampAsync(User user, string stamp) + { + user.SecurityStamp = stamp; + return Task.CompletedTask; + } + + #endregion IUserSecurityStampStore + + #region IUserLockoutStore + + public Task GetAccessFailedCountAsync(User user) + { + return Task.FromResult(user.AccessFailedCount); + } + + public Task GetLockoutEnabledAsync(User user) + { + return Task.FromResult(user.LockoutEnabled); + } + + public Task GetLockoutEndDateAsync(User user) + { + DateTimeOffset dateTimeOffset; + + if (user.LockoutEndDate.HasValue) + { + var lockoutEndDate = user.LockoutEndDate; + dateTimeOffset = new DateTimeOffset(DateTime.SpecifyKind(lockoutEndDate.Value, DateTimeKind.Utc)); + } + else + { + dateTimeOffset = new DateTimeOffset(); + } + return Task.FromResult(dateTimeOffset); throw new NotImplementedException(); + } + + public Task IncrementAccessFailedCountAsync(User user) + { + user.AccessFailedCount = user.AccessFailedCount + 1; + return Task.FromResult(user.AccessFailedCount); + } + + public Task ResetAccessFailedCountAsync(User user) + { + user.AccessFailedCount = 0; + return Task.CompletedTask; + } + + public Task SetLockoutEnabledAsync(User user, bool enabled) + { + user.LockoutEnabled = enabled; + return Task.CompletedTask; + } + + public Task SetLockoutEndDateAsync(User user, DateTimeOffset lockoutEnd) + { + user.LockoutEndDate = lockoutEnd.UtcDateTime; ; + return Task.CompletedTask; + } + + #endregion IUserLockoutStore + + #region IUserTwoFactorStore + + public Task GetTwoFactorEnabledAsync(User user) + { + return Task.FromResult(false); + } + + /// + /// + /// + /// + /// + /// + public Task SetTwoFactorEnabledAsync(User user, bool enabled) + { + user.IsTwoFactorEnabled = false; + return Task.CompletedTask; + } + + #endregion IUserTwoFactorStore + } +} \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services/Utilities/EmailService.cs b/Components/AAA/BExIS.Security.Services/Utilities/EmailService.cs index df4ffd94d1..81300b896c 100644 --- a/Components/AAA/BExIS.Security.Services/Utilities/EmailService.cs +++ b/Components/AAA/BExIS.Security.Services/Utilities/EmailService.cs @@ -56,6 +56,8 @@ public void Send(MimeMessage message) { try { + if(!_smtpConfiguration.IsActive) return; + using (var client = new SmtpClient()) { // 2021-03-16 by Sven diff --git a/Components/AAA/BExIS.Security.Services/Versions/VersionManager.cs b/Components/AAA/BExIS.Security.Services/Versions/VersionManager.cs index 6f9812c98b..00becb4863 100644 --- a/Components/AAA/BExIS.Security.Services/Versions/VersionManager.cs +++ b/Components/AAA/BExIS.Security.Services/Versions/VersionManager.cs @@ -5,113 +5,82 @@ namespace BExIS.Security.Services.Versions { - public class VersionManager : IDisposable + public class VersionManager { - private readonly IUnitOfWork _guow; - private bool _isDisposed; - - public VersionManager() - { - _guow = this.GetIsolatedUnitOfWork(); - VersionRepository = _guow.GetReadOnlyRepository(); - } - - ~VersionManager() - { - Dispose(true); - } - - public IReadOnlyRepository VersionRepository { get; } - - public IQueryable Versions => VersionRepository.Query(); - - public Version LatestVersion => VersionRepository.Query().OrderByDescending(v => v.Date).FirstOrDefault(); - - public void Dispose() - { - Dispose(true); - } - public Version GetLatestVersion(string module = "Shell") { + if (string.IsNullOrWhiteSpace(module)) + return null; + using (var uow = this.GetUnitOfWork()) { - return !Exists(module) ? null : VersionRepository.Query(v => v.Module.Equals(module)).OrderByDescending(v => v.Date).FirstOrDefault(); + var versionsRepository = uow.GetReadOnlyRepository(); + return versionsRepository.Query(v => v.Module == module) + .OrderByDescending(v => v.Date) + .FirstOrDefault(); } } - protected void Dispose(bool disposing) + public void Update(Version version) { - if (!_isDisposed) - { - if (disposing) - { - _guow?.Dispose(); - _isDisposed = true; - } - } - } + if (version == null) + throw new ArgumentNullException(nameof(version)); - public void Update(Version entity) - { using (var uow = this.GetUnitOfWork()) { - var repo = uow.GetRepository(); - repo.Merge(entity); - var merged = repo.Get(entity.Id); + var versionsRepository = uow.GetRepository(); + versionsRepository.Merge(version); + var merged = versionsRepository.Get(version.Id); merged.Date = DateTime.Now; - repo.Put(merged); + versionsRepository.Put(merged); uow.Commit(); } } public bool Exists(string module, string value) { - using (var uow = this.GetUnitOfWork()) - { - var operationRepository = uow.GetReadOnlyRepository(); - - if (string.IsNullOrEmpty(module)) - return false; + if (string.IsNullOrEmpty(module)) + return false; - if (string.IsNullOrEmpty(value)) - return false; - - return operationRepository.Query(v => v.Module.ToUpperInvariant() == module.ToUpperInvariant() && v.Value.ToUpperInvariant() == value.ToUpperInvariant()).Count() == 1; - } - } + if (string.IsNullOrEmpty(value)) + return false; - public bool Exists(string module) - { using (var uow = this.GetUnitOfWork()) { - var operationRepository = uow.GetReadOnlyRepository(); - - if (string.IsNullOrEmpty(module)) - return false; - - return operationRepository.Query(v => v.Module.ToUpperInvariant() == module.ToUpperInvariant()).Any(); + var versionsRepository = uow.GetReadOnlyRepository(); + return versionsRepository.Query(v => v.Module == module && v.Value == value).Any(); } } public Version Create(string module, string value) { + if (string.IsNullOrWhiteSpace(module)) + throw new ArgumentException(nameof(module)); + + if (string.IsNullOrWhiteSpace(value)) + throw new ArgumentException(nameof(value)); + using (var uow = this.GetUnitOfWork()) { - if (Exists(module, value)) + var versionsRepository = uow.GetRepository(); + + var exists = versionsRepository.Query(v => + v.Module == module && + v.Value == value).Any(); + + if (exists) return null; - var version = new Version() + var version = new Version { Module = module, Value = value, Date = DateTime.Now }; - var versionRepository = uow.GetRepository(); - versionRepository.Put(version); + versionsRepository.Put(version); uow.Commit(); return version; diff --git a/Components/AAA/BExIS.Security.Services/packages.config b/Components/AAA/BExIS.Security.Services/packages.config index a4c16ea9d1..96699880e5 100644 --- a/Components/AAA/BExIS.Security.Services/packages.config +++ b/Components/AAA/BExIS.Security.Services/packages.config @@ -1,6 +1,8 @@  + + @@ -17,10 +19,13 @@ - + + + + diff --git a/Components/App/BExIS.App.Bootstrap/Application.cs b/Components/App/BExIS.App.Bootstrap/Application.cs index d3d04d8fcc..67f5cab952 100644 --- a/Components/App/BExIS.App.Bootstrap/Application.cs +++ b/Components/App/BExIS.App.Bootstrap/Application.cs @@ -1,12 +1,22 @@ using BExIS.App.Bootstrap.Attributes; using BExIS.Ext.Services; using BExIS.Utils.Config; +using BExIS.Utils.Config.Configurations; +using Microsoft.Owin; +using Microsoft.Owin.Host.SystemWeb; +using Microsoft.Owin.Security; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net; +using System.Reflection; +using System.Runtime; using System.Threading; +using System.Web; using System.Web.Http; +using System.Web.Http.Dispatcher; using System.Web.Mvc; using System.Web.Routing; using Vaiona.IoC; @@ -128,7 +138,26 @@ private void application_Start(Action configurationCallback, // This MUST be before IoC initialization. AppDomain.CurrentDomain.AssemblyResolve += ModuleManager.ResolveCurrentDomainAssembly; initIoC(); - GlobalConfiguration.Configure(configurationCallback); + + // ================================================ + // Web API konfigurieren + unseren Activator setzen + // ================================================ + GlobalConfiguration.Configure(config => + { + // Deine bestehende Konfiguration (falls du eine Callback-Methode hast) + configurationCallback?.Invoke(config); + + // WICHTIG: Hier den Unity Activator für alle ApiController registrieren + config.Services.Replace( + typeof(IHttpControllerActivator), + new UnityHttpControllerActivator() + ); + + // Optional: Vollständiger Dependency Resolver (für Filter, etc.) + // config.DependencyResolver = new UnityDependencyResolver(IoCFactory.Container); + }); + + //GlobalConfiguration.Configure(configurationCallback); // This method initializes the registered modules. It MUST be before initializing the persistence! initModules(); @@ -145,7 +174,9 @@ private void application_Start(Action configurationCallback, // This call starts them. ModuleManager.StartModules(); - // generate settings + ControllerBuilder.Current.SetControllerFactory(new IoCControllerFactory()); + + GeneralSettings.CreateIssuerSigningKey(); } private void initTenancy() diff --git a/Components/App/BExIS.App.Bootstrap/Attributes/BExISApiAuthorizeAttribute.cs b/Components/App/BExIS.App.Bootstrap/Attributes/BExISApiAuthorizeAttribute.cs index 65fcc59307..063a6a7c6e 100644 --- a/Components/App/BExIS.App.Bootstrap/Attributes/BExISApiAuthorizeAttribute.cs +++ b/Components/App/BExIS.App.Bootstrap/Attributes/BExISApiAuthorizeAttribute.cs @@ -14,6 +14,7 @@ using System.Web; using System.Web.Http; using System.Web.Http.Controllers; +using Vaiona.IoC; namespace BExIS.App.Bootstrap.Attributes { @@ -25,9 +26,9 @@ public override void OnAuthorization(HttpActionContext actionContext) { using (var featurePermissionManager = new FeaturePermissionManager()) using (var operationManager = new OperationManager()) - using (var userManager = new UserManager()) - using (var identityUserService = new IdentityUserService(userManager)) { + var userManager = IoCFactory.Container.Resolve(); + var areaName = "Api"; var controllerName = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName; var actionName = actionContext.ActionDescriptor.ActionName; @@ -101,7 +102,7 @@ public override void OnAuthorization(HttpActionContext actionContext) return; } - var result = identityUserService.CheckPasswordAsync(user, Encoding.UTF8.GetString(Convert.FromBase64String(basicParameter)).Split(':')[1]).Result; + var result = userManager.CheckPasswordAsync(user, Encoding.UTF8.GetString(Convert.FromBase64String(basicParameter)).Split(':')[1]).Result; if (!result) { @@ -136,10 +137,10 @@ public override void OnAuthorization(HttpActionContext actionContext) actionContext.ControllerContext.RouteData.Values.Add("user", user); + var jwtConfiguration = GeneralSettings.JwtConfiguration; // update jwt cookie - if (user != null) + if (user != null && jwtConfiguration.IsActive) { - var jwtConfiguration = GeneralSettings.JwtConfiguration; var jwt = JwtHelper.GetTokenByUser(user); // Create a new cookie @@ -159,6 +160,9 @@ public override void OnAuthorization(HttpActionContext actionContext) } catch (Exception ex) { + actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden); + actionContext.Response.Content = new StringContent("The system denied the access."); + return; } } diff --git a/Components/App/BExIS.App.Bootstrap/Attributes/BExISAuthorizeAttribute.cs b/Components/App/BExIS.App.Bootstrap/Attributes/BExISAuthorizeAttribute.cs index 0893ef22d7..685d278143 100644 --- a/Components/App/BExIS.App.Bootstrap/Attributes/BExISAuthorizeAttribute.cs +++ b/Components/App/BExIS.App.Bootstrap/Attributes/BExISAuthorizeAttribute.cs @@ -4,12 +4,13 @@ using BExIS.Security.Services.Authorization; using BExIS.Security.Services.Objects; using BExIS.Security.Services.Subjects; +using BExIS.Utils.Config; using System; using System.Linq; using System.Net; using System.Web; using System.Web.Mvc; -using BExIS.Utils.Config; +using Vaiona.IoC; namespace BExIS.App.Bootstrap.Attributes { @@ -21,9 +22,8 @@ public override void OnAuthorization(AuthorizationContext filterContext) { using (var featurePermissionManager = new FeaturePermissionManager()) using (var operationManager = new OperationManager()) - using (var userManager = new UserManager()) - using (var identityUserService = new IdentityUserService(userManager)) { + var userManager = IoCFactory.Container.Resolve(); var areaName = filterContext.RouteData.DataTokens.Keys.Contains("area") ? filterContext.RouteData.DataTokens["area"].ToString() : "Shell"; var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; var actionName = filterContext.ActionDescriptor.ActionName; diff --git a/Components/App/BExIS.App.Bootstrap/Attributes/BExISEntityAuthorizeAttribute.cs b/Components/App/BExIS.App.Bootstrap/Attributes/BExISEntityAuthorizeAttribute.cs index 3709e8948d..03549cb411 100644 --- a/Components/App/BExIS.App.Bootstrap/Attributes/BExISEntityAuthorizeAttribute.cs +++ b/Components/App/BExIS.App.Bootstrap/Attributes/BExISEntityAuthorizeAttribute.cs @@ -7,6 +7,7 @@ using System; using System.Web.Mvc; using System.Web.Routing; +using Vaiona.IoC; namespace BExIS.App.Bootstrap.Attributes { @@ -29,7 +30,7 @@ public BExISEntityAuthorizeAttribute(Type entityType, string keyName, RightType public async override void OnActionExecuting(ActionExecutingContext filterContext) { var entityPermissionManager = new EntityPermissionManager(); - var userManager = new UserManager(); + var userManager = IoCFactory.Container.Resolve(); try { @@ -69,7 +70,6 @@ public async override void OnActionExecuting(ActionExecutingContext filterContex } finally { - entityPermissionManager.Dispose(); userManager.Dispose(); } } diff --git a/Components/App/BExIS.App.Bootstrap/BExIS.App.Bootstrap.csproj b/Components/App/BExIS.App.Bootstrap/BExIS.App.Bootstrap.csproj index 0ac9743cfa..c78dccec26 100644 --- a/Components/App/BExIS.App.Bootstrap/BExIS.App.Bootstrap.csproj +++ b/Components/App/BExIS.App.Bootstrap/BExIS.App.Bootstrap.csproj @@ -44,6 +44,9 @@ ..\..\..\packages\Microsoft.AspNet.Identity.Core.2.2.4\lib\net45\Microsoft.AspNet.Identity.Core.dll + + ..\..\..\packages\Microsoft.AspNet.Identity.Owin.2.2.4\lib\net45\Microsoft.AspNet.Identity.Owin.dll + ..\..\..\packages\Microsoft.IdentityModel.JsonWebTokens.5.7.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll @@ -53,11 +56,29 @@ ..\..\..\packages\Microsoft.IdentityModel.Tokens.5.7.0\lib\net461\Microsoft.IdentityModel.Tokens.dll + + ..\..\..\packages\Microsoft.Owin.4.2.2\lib\net45\Microsoft.Owin.dll + + + ..\..\..\packages\Microsoft.Owin.Host.SystemWeb.4.2.2\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + + + ..\..\..\packages\Microsoft.Owin.Security.4.2.2\lib\net45\Microsoft.Owin.Security.dll + + + ..\..\..\packages\Microsoft.Owin.Security.Cookies.4.2.2\lib\net45\Microsoft.Owin.Security.Cookies.dll + + + ..\..\..\packages\Microsoft.Owin.Security.OAuth.4.2.2\lib\net45\Microsoft.Owin.Security.OAuth.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll + + + ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll @@ -70,6 +91,7 @@ ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + ..\..\..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll @@ -114,9 +136,12 @@ + + + diff --git a/Components/App/BExIS.App.Bootstrap/Extensions/IdentityExtensions.cs b/Components/App/BExIS.App.Bootstrap/Extensions/IdentityExtensions.cs new file mode 100644 index 0000000000..e9a645d8f7 --- /dev/null +++ b/Components/App/BExIS.App.Bootstrap/Extensions/IdentityExtensions.cs @@ -0,0 +1,38 @@ +using System.Security.Principal; +using System.Security.Claims; + +namespace BExIS.App.Bootstrap.Extensions +{ + public static class IdentityExtensions + { + public static string GetDisplayName(this IPrincipal principal) + { + if (principal == null) + return null; + + var identity = principal.Identity; + if (identity == null || !identity.IsAuthenticated) + return null; + + // Sicherer Weg: als ClaimsIdentity casten + if (identity is ClaimsIdentity claimsIdentity) + { + var displayNameClaim = claimsIdentity.FindFirst("DisplayName"); + if (displayNameClaim != null) + { + return displayNameClaim.Value; + } + + // Fallback auf andere bekannte Claim-Typen (falls du mal umbenennst) + var nameClaim = claimsIdentity.FindFirst(ClaimTypes.Name) + ?? claimsIdentity.FindFirst("name") + ?? claimsIdentity.FindFirst(ClaimTypes.GivenName); + + return nameClaim?.Value ?? identity.Name ?? string.Empty; + } + + // Sehr alter oder nicht-Claims-basierter Principal + return identity.Name ?? string.Empty; + } + } +} diff --git a/Components/App/BExIS.App.Bootstrap/Helpers/BExISAuthorizeHelper.cs b/Components/App/BExIS.App.Bootstrap/Helpers/BExISAuthorizeHelper.cs index 28b016f299..4d7b5753b9 100644 --- a/Components/App/BExIS.App.Bootstrap/Helpers/BExISAuthorizeHelper.cs +++ b/Components/App/BExIS.App.Bootstrap/Helpers/BExISAuthorizeHelper.cs @@ -2,11 +2,13 @@ using BExIS.Security.Services.Authorization; using BExIS.Security.Services.Objects; using BExIS.Security.Services.Subjects; +using Microsoft.AspNet.Identity; using System; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using System.Web; +using Vaiona.IoC; namespace BExIS.App.Bootstrap.Helpers { @@ -33,8 +35,9 @@ public static User GetUserFromAuthorization(string authorisation, out User user) { using (var featurePermissionManager = new FeaturePermissionManager()) using (var operationManager = new OperationManager()) - using (var userManager = new UserManager()) { + var userManager = IoCFactory.Container.Resolve(); + if (string.IsNullOrEmpty(authorisation)) { user = null; @@ -63,24 +66,21 @@ public static User GetUserFromAuthorization(string authorisation, out User user) var basic = code; if (basic != null) { - using (var identityUserService = new IdentityUserService(userManager)) + user = userManager.FindByNameAsync(System.Text.Encoding.UTF8.GetString( + Convert.FromBase64String(basic)).Split(':')[0]).Result; + + if (user != null) { - user = userManager.FindByNameAsync(System.Text.Encoding.UTF8.GetString( - Convert.FromBase64String(basic)).Split(':')[0]).Result; + var result = userManager.CheckPasswordAsync(user, System.Text.Encoding.UTF8.GetString( + Convert.FromBase64String(basic)).Split(':')[1]).Result; - if (user != null) + if (!result) { - var result = identityUserService.CheckPasswordAsync(user, System.Text.Encoding.UTF8.GetString( - Convert.FromBase64String(basic)).Split(':')[1]).Result; - - if (!result) - { - return null; - } + return null; } - - return user; } + + return user; } } @@ -91,43 +91,41 @@ public static User GetUserFromAuthorization(string authorisation, out User user) public static User GetUserFromAuthorization(HttpContextBase context) { - using (UserManager userManager = new UserManager()) - { - User user = null; - string userName = ""; - if (context.User.Identity.IsAuthenticated) - { - var userTask = userManager.FindByNameAsync(context.User.Identity.Name); - userTask.Wait(); - user = userTask.Result; - } - else - { - var authorization = context.Request.Headers.Get("Authorization"); - GetUserFromAuthorization(authorization, out user); - } + var userManager = IoCFactory.Container.Resolve(); - return user; + User user = null; + string userName = ""; + if (context.User.Identity.IsAuthenticated) + { + var userTask = userManager.FindByNameAsync(context.User.Identity.Name); + userTask.Wait(); + user = userTask.Result; + } + else + { + var authorization = context.Request.Headers.Get("Authorization"); + GetUserFromAuthorization(authorization, out user); } + + return user; } public static async Task GetUserFromAuthorizationAsync(HttpContextBase context) { try { - using (var userManager = new UserManager()) - { - var identity = context.User?.Identity; + var userManager = IoCFactory.Container.Resolve(); - if (identity != null && identity.IsAuthenticated) - { - return await userManager.FindByNameAsync(identity.Name); - } - else - { - var authorization = context.Request.Headers.Get("Authorization"); - return await GetUserFromAuthorizationAsync(authorization); - } + var identity = context.User?.Identity; + + if (identity != null && identity.IsAuthenticated) + { + return await userManager.FindByNameAsync(identity.Name); + } + else + { + var authorization = context.Request.Headers.Get("Authorization"); + return await GetUserFromAuthorizationAsync(authorization); } } catch (Exception ex) @@ -140,39 +138,37 @@ public static async Task GetUserFromAuthorizationAsync(string authorizatio { try { - using (var userManager = new UserManager()) - using (var identityUserService = new IdentityUserService(userManager)) + var userManager = IoCFactory.Container.Resolve(); + + if (string.IsNullOrEmpty(authorization)) { - if (string.IsNullOrEmpty(authorization)) - { - return null; - } + return null; + } - var authorizationArray = authorization.Split(' '); - var type = authorizationArray[0]; - var value = authorizationArray[1]; + var authorizationArray = authorization.Split(' '); + var type = authorizationArray[0]; + var value = authorizationArray[1]; - switch (type.ToLower()) - { - case "bearer": - return null; + switch (type.ToLower()) + { + case "bearer": + return null; - case "basic": - var basicArray = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(value)).Split(':'); + case "basic": + var basicArray = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(value)).Split(':'); - if (basicArray.Length == 2) - { - var user = await userManager.FindByNameAsync(basicArray[0]); + if (basicArray.Length == 2) + { + var user = await userManager.FindByNameAsync(basicArray[0]); - if (user != null && await identityUserService.CheckPasswordAsync(user, basicArray[1])) - return user; - } + if (user != null && await userManager.CheckPasswordAsync(user, basicArray[1])) + return user; + } - return null; + return null; - default: - return null; - } + default: + return null; } } catch (Exception ex) @@ -196,8 +192,10 @@ public static HttpResponseMessage HttpRequestAuthorization(string authorisation, using (var featurePermissionManager = new FeaturePermissionManager()) using (var operationManager = new OperationManager()) - using (var userManager = new UserManager()) { + var userManager = IoCFactory.Container.Resolve(); + + if (string.IsNullOrEmpty(authorisation)) { response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); @@ -240,31 +238,28 @@ public static HttpResponseMessage HttpRequestAuthorization(string authorisation, var basic = code; if (basic != null) { - using (var identityUserService = new IdentityUserService(userManager)) + user = userManager.FindByNameAsync(System.Text.Encoding.UTF8.GetString( + Convert.FromBase64String(basic)).Split(':')[0]).Result; + + if (user != null) { - user = userManager.FindByNameAsync(System.Text.Encoding.UTF8.GetString( - Convert.FromBase64String(basic)).Split(':')[0]).Result; + var result = userManager.CheckPasswordAsync(user, System.Text.Encoding.UTF8.GetString( + Convert.FromBase64String(basic)).Split(':')[1]).Result; - if (user != null) + if (!result) { - var result = identityUserService.CheckPasswordAsync(user, System.Text.Encoding.UTF8.GetString( - Convert.FromBase64String(basic)).Split(':')[1]).Result; - - if (!result) - { - response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); - response.Content = new StringContent("UserName and/or Password are incorrect."); - } - - if (!featurePermissionManager.HasAccessAsync(user.Id, featureId).Result) - { - response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); - response.Content = new StringContent("User is not valid."); - } + response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); + response.Content = new StringContent("UserName and/or Password are incorrect."); } - return response; + if (!featurePermissionManager.HasAccessAsync(user.Id, featureId).Result) + { + response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); + response.Content = new StringContent("User is not valid."); + } } + + return response; } } diff --git a/Components/App/BExIS.App.Bootstrap/IoCControllerFactory.cs b/Components/App/BExIS.App.Bootstrap/IoCControllerFactory.cs new file mode 100644 index 0000000000..e771e7ff75 --- /dev/null +++ b/Components/App/BExIS.App.Bootstrap/IoCControllerFactory.cs @@ -0,0 +1,45 @@ +using System; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using Vaiona.IoC; + +namespace BExIS.App.Bootstrap +{ + public class IoCControllerFactory : DefaultControllerFactory + { + protected override IController GetControllerInstance( + RequestContext requestContext, + Type controllerType) + { + // Fall 1: MVC konnte den Controller-Typ nicht finden (z. B. "wp-includes", "dasisteintest") + if (controllerType == null) + { + // WICHTIG: HttpException 404 werfen → MVC behandelt das als 404 + throw new HttpException(404, "The requested controller was not found."); + } + + try + { + // Versuch, den Controller über Unity aufzulösen + var controller = IoCFactory.Container.Resolve(controllerType) as IController; + + if (controller == null) + { + throw new HttpException(404, $"Could not create controller instance for type: {controllerType.FullName}"); + } + + return controller; + } + catch (Exception ex) + { + // Loggen (empfohlen) + // Vaiona.Logging.ILogger.LogError(ex, $"Controller resolution failed for {controllerType.FullName}"); + + // HttpException 404 werfen → sauberes 404 statt InvalidOperationException + throw new HttpException(404, + $"The controller '{controllerType.Name}' could not be created.", ex); + } + } + } +} \ No newline at end of file diff --git a/Components/App/BExIS.App.Bootstrap/UnityHttpControllerActivator.cs b/Components/App/BExIS.App.Bootstrap/UnityHttpControllerActivator.cs new file mode 100644 index 0000000000..4a7a26618f --- /dev/null +++ b/Components/App/BExIS.App.Bootstrap/UnityHttpControllerActivator.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http; +using System.Web.Http.Controllers; +using System.Web.Http.Dispatcher; +using Vaiona.IoC; + +namespace BExIS.App.Bootstrap +{ + public class UnityHttpControllerActivator : IHttpControllerActivator + { + public IHttpController Create( + HttpRequestMessage request, + HttpControllerDescriptor controllerDescriptor, + Type controllerType) + { + if (controllerType == null) + throw new ArgumentNullException(nameof(controllerType)); + + try + { + // Hier wird der ApiController mit allen Dependencies über Unity aufgelöst + var controller = IoCFactory.Container.Resolve(controllerType) as IHttpController; + + if (controller == null) + { + throw new InvalidOperationException( + $"Unity konnte keinen Instanz für ApiController {controllerType.FullName} erstellen."); + } + + return controller; + } + catch (Exception ex) + { + // Optional: Logging + // Vaiona.Logging.ILogger.LogError(ex, $"ApiController activation failed: {controllerType.FullName}"); + + // Saubere Fehlerantwort für die API + throw new HttpResponseException( + request.CreateErrorResponse( + System.Net.HttpStatusCode.InternalServerError, + $"Fehler beim Erstellen des Controllers {controllerType.Name}: {ex.Message}")); + } + } + } +} diff --git a/Components/App/BExIS.App.Bootstrap/packages.config b/Components/App/BExIS.App.Bootstrap/packages.config index d6ed517ae5..d8ae80171e 100644 --- a/Components/App/BExIS.App.Bootstrap/packages.config +++ b/Components/App/BExIS.App.Bootstrap/packages.config @@ -1,9 +1,18 @@  + + + + + + + + + \ No newline at end of file diff --git a/Components/App/BExIS.App.Testing/BExIS.App.Testing.csproj b/Components/App/BExIS.App.Testing/BExIS.App.Testing.csproj index d99220c3ab..2ad625e6dc 100644 --- a/Components/App/BExIS.App.Testing/BExIS.App.Testing.csproj +++ b/Components/App/BExIS.App.Testing/BExIS.App.Testing.csproj @@ -45,6 +45,9 @@ ..\..\..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll + + ..\..\..\packages\FluentAssertions.5.10.3\lib\net47\FluentAssertions.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll @@ -52,7 +55,7 @@ ..\..\..\packages\Moq.4.8.1\lib\net45\Moq.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\NUnit.3.14.0\lib\net45\nunit.framework.dll @@ -65,9 +68,10 @@ ..\..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + True - - ..\..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + ..\..\..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll ..\..\..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll @@ -94,6 +98,8 @@ ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.WebPages.Razor.dll + + diff --git a/Components/App/BExIS.App.Testing/packages.config b/Components/App/BExIS.App.Testing/packages.config index 6294bc1bf7..c6e98aac90 100644 --- a/Components/App/BExIS.App.Testing/packages.config +++ b/Components/App/BExIS.App.Testing/packages.config @@ -1,6 +1,7 @@  + @@ -9,12 +10,12 @@ - + - + \ No newline at end of file diff --git a/Components/DLM/BExIS.Dlm.Entities/BExIS.Dlm.Entities.csproj b/Components/DLM/BExIS.Dlm.Entities/BExIS.Dlm.Entities.csproj index 2f6192e4bd..600c5452ba 100644 --- a/Components/DLM/BExIS.Dlm.Entities/BExIS.Dlm.Entities.csproj +++ b/Components/DLM/BExIS.Dlm.Entities/BExIS.Dlm.Entities.csproj @@ -52,7 +52,7 @@ - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs b/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs index 2049032591..67f483a53d 100644 --- a/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs +++ b/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs @@ -17,6 +17,11 @@ public class EntityTemplate : BaseEntity /// public virtual string Description { get; set; } + /// + /// Description of the Entity Template + /// + public virtual int Order { get; set; } + /// /// Entity /// @@ -169,7 +174,7 @@ public EntityTemplate() PermissionGroups = new PermissionsType(); NotificationGroups = new List(); MetadataInvalidSaveMode = true; - + Order = 0; JsonAllowedFileTypes = ""; JsonDatastructureList = ""; JsonDisabledHooks = ""; diff --git a/Components/DLM/BExIS.Dlm.Entities/packages.config b/Components/DLM/BExIS.Dlm.Entities/packages.config index f50702e7f9..a2eabe2ead 100644 --- a/Components/DLM/BExIS.Dlm.Entities/packages.config +++ b/Components/DLM/BExIS.Dlm.Entities/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/Data/EntityTemplate.hbm.xml b/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/Data/EntityTemplate.hbm.xml index 59d4a5c1cd..6e4b3ddff9 100644 --- a/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/Data/EntityTemplate.hbm.xml +++ b/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/Data/EntityTemplate.hbm.xml @@ -28,6 +28,10 @@ + + + + diff --git a/Components/DLM/BExIS.Dlm.Services/BExIS.Dlm.Services.csproj b/Components/DLM/BExIS.Dlm.Services/BExIS.Dlm.Services.csproj index f0aedfb538..d131d355b9 100644 --- a/Components/DLM/BExIS.Dlm.Services/BExIS.Dlm.Services.csproj +++ b/Components/DLM/BExIS.Dlm.Services/BExIS.Dlm.Services.csproj @@ -127,7 +127,7 @@ ..\..\..\packages\NCalc-Edge.1.4.3\lib\NCalc.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/DLM/BExIS.Dlm.Services/DataStructure/VariableManager.cs b/Components/DLM/BExIS.Dlm.Services/DataStructure/VariableManager.cs index 56603ef6b7..b7a251d1ba 100644 --- a/Components/DLM/BExIS.Dlm.Services/DataStructure/VariableManager.cs +++ b/Components/DLM/BExIS.Dlm.Services/DataStructure/VariableManager.cs @@ -400,8 +400,8 @@ public VariableInstance UpdateVariable(VariableInstance entity) merged.VariableTemplate = entity.VariableTemplate; merged.VariableConstraints = entity.VariableConstraints; merged.Meanings = entity.Meanings; - merged.MissingValues = entity.MissingValues; - merged.Description = entity.Description; + merged.Description = entity.Description; + repo.Put(merged); uow.Commit(); } @@ -617,15 +617,10 @@ public string getPlaceholder(TypeCode typeCode, List missingValues case TypeCode.String: try { - int temp = DateTime.Now.Ticks.GetHashCode(); - List placeholders = missingValues.Select(mv => mv.Placeholder).ToList(); - - while (placeholders.Contains(temp.ToString(format))) - { - temp += 1; - } - - return temp.ToString(format); + var x = missingValues.First(mv => mv.Placeholder == null); + if (x != null) return x.DisplayName; + + return ""; } catch { diff --git a/Components/DLM/BExIS.Dlm.Services/Party/PartyManager.cs b/Components/DLM/BExIS.Dlm.Services/Party/PartyManager.cs index 9df728531d..95c9ba99cc 100644 --- a/Components/DLM/BExIS.Dlm.Services/Party/PartyManager.cs +++ b/Components/DLM/BExIS.Dlm.Services/Party/PartyManager.cs @@ -245,6 +245,7 @@ public PartyX Update(PartyX newParty) party.StartDate = DateTime.MinValue; if (party.EndDate == null || party.EndDate == DateTime.MinValue) party.EndDate = DateTime.MaxValue; + if (party.StartDate > party.EndDate) BexisException.Throw(null, "End date should be greater than start date."); if ((ValidateRelationships(party.Id)).Any()) @@ -1137,4 +1138,5 @@ private PartyX UpdatePartyName(PartyX party) #endregion privateMethod } -} \ No newline at end of file + +} diff --git a/Components/DLM/BExIS.Dlm.Services/packages.config b/Components/DLM/BExIS.Dlm.Services/packages.config index 6e824a51f8..76fa0334fd 100644 --- a/Components/DLM/BExIS.Dlm.Services/packages.config +++ b/Components/DLM/BExIS.Dlm.Services/packages.config @@ -3,6 +3,6 @@ - + \ No newline at end of file diff --git a/Components/DLM/BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj b/Components/DLM/BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj index 204b99e14c..752f098988 100644 --- a/Components/DLM/BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj +++ b/Components/DLM/BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj @@ -85,7 +85,7 @@ ..\..\..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\Npgsql.4.0.17\lib\net451\Npgsql.dll @@ -180,6 +180,10 @@ {0815d220-3625-4e23-bbbc-8152345637fe} Vaiona.Entities + + {29A7BE0F-A17C-4AE8-8CA1-15FE4DD74129} + Vaiona.IoC + {640bf81d-354a-4bf0-85fc-f0ad587cf8a2} Vaiona.Persistence.Api diff --git a/Components/DLM/BExIS.Dlm.Tests/Services/Curation/CurationEntryTests.cs b/Components/DLM/BExIS.Dlm.Tests/Services/Curation/CurationEntryTests.cs index f13d9955c3..5f5b4b23f3 100644 --- a/Components/DLM/BExIS.Dlm.Tests/Services/Curation/CurationEntryTests.cs +++ b/Components/DLM/BExIS.Dlm.Tests/Services/Curation/CurationEntryTests.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Vaiona.IoC; using Vaiona.Persistence.Api; namespace BExIS.Dlm.Tests.Services.Curation @@ -23,39 +24,43 @@ namespace BExIS.Dlm.Tests.Services.Curation public class CurationEntryTests { private TestSetupHelper helper = null; + private GroupManager _groupManager; + public CurationEntryTests() + { + //_groupManager = new GroupManager(); + } + public CurationEntryTests(GroupManager groupManager) + { + _groupManager = groupManager; + } [OneTimeSetUp] public void OneTimeSetUp() { helper = new TestSetupHelper(WebApiConfig.Register, false); - using (UserManager userManager = new UserManager()) - using (GroupManager groupManager = new GroupManager()) - { - Group group = new Group(); - group.Name = "curator"; - group.Description = "curators group"; - groupManager.CreateAsync(group); + var userManager = IoCFactory.Container.Resolve(); - + Group group = new Group(); + group.Name = "curator"; + group.Description = "curators group"; + _groupManager.CreateAsync(group); - User admin = new User() - { - Name = "Admin", - DisplayName = "Admin", - Email = "bexis2-support@uni-jena.de" - }; - - userManager.CreateAsync(admin).Wait(); - admin = userManager.FindByNameAsync("Admin").Result; - group = groupManager.FindByNameAsync("curator").Result; - userManager.AddToRoleAsync(admin, group.Name).Wait(); + User admin = new User() + { + Name = "Admin", + DisplayName = "Admin", + Email = "bexis2-support@uni-jena.de" + }; + userManager.CreateAsync(admin).Wait(); + admin = userManager.FindByNameAsync("Admin").Result; + group = _groupManager.FindByNameAsync("curator").Result; - } + userManager.AddToRoleAsync(admin.Id, group.Name).Wait(); } [SetUp] @@ -111,14 +116,14 @@ public void OneTimeTearDown() } - [Test()] + //[Test()] public void Create_valid_CurationEntry() { //act using (var curationEntryManager = new CurationManager()) - using (var userManager = new UserManager()) { + var userManager = IoCFactory.Container.Resolve(); //Arrange var dsHelper = new DatasetHelper(); @@ -149,14 +154,14 @@ public void Create_valid_CurationEntry() } } - [Test()] + //[Test()] public void Delete_valid_CurationEntry() { //act using (var curationEntryManager = new CurationManager()) - using (var userManager = new UserManager()) { + var userManager = IoCFactory.Container.Resolve(); //Arrange var dsHelper = new DatasetHelper(); diff --git a/Components/DLM/BExIS.Dlm.Tests/packages.config b/Components/DLM/BExIS.Dlm.Tests/packages.config index 4774248979..80996147d8 100644 --- a/Components/DLM/BExIS.Dlm.Tests/packages.config +++ b/Components/DLM/BExIS.Dlm.Tests/packages.config @@ -8,7 +8,7 @@ - + diff --git a/Components/EXT/BExIS.Ext.Services/AuthorizationDelegationImplementor.cs b/Components/EXT/BExIS.Ext.Services/AuthorizationDelegationImplementor.cs index 8afda89bae..4031c08b41 100644 --- a/Components/EXT/BExIS.Ext.Services/AuthorizationDelegationImplementor.cs +++ b/Components/EXT/BExIS.Ext.Services/AuthorizationDelegationImplementor.cs @@ -2,6 +2,7 @@ using BExIS.Security.Services.Objects; using BExIS.Security.Services.Subjects; using System; +using Vaiona.IoC; namespace BExIS.Ext.Services { @@ -17,8 +18,9 @@ public static void CheckAuthorization(string areaName, string controllerName, st using (var operationManager = new OperationManager()) using (var featurePermissionManager = new FeaturePermissionManager()) - using (var userManager = new UserManager()) { + var userManager = IoCFactory.Container.Resolve(); + var operation = operationManager.Find(areaName, controllerName, "*"); if (operation == null) { diff --git a/Components/EXT/BExIS.Ext.Services/BExIS.Ext.Services.csproj b/Components/EXT/BExIS.Ext.Services/BExIS.Ext.Services.csproj index efb93daf82..8053266ad3 100644 --- a/Components/EXT/BExIS.Ext.Services/BExIS.Ext.Services.csproj +++ b/Components/EXT/BExIS.Ext.Services/BExIS.Ext.Services.csproj @@ -77,6 +77,10 @@ {0815d220-3625-4e23-bbbc-8152345637fe} Vaiona.Entities + + {29A7BE0F-A17C-4AE8-8CA1-15FE4DD74129} + Vaiona.IoC + {4639d130-e0aa-4aef-b9bd-bef6ad99dbaf} Vaiona.MultiTenancy.Services diff --git a/Components/IO/BExIS.IO.Tests/BExIS.IO.Tests.csproj b/Components/IO/BExIS.IO.Tests/BExIS.IO.Tests.csproj index e784b1aad4..977f850a22 100644 --- a/Components/IO/BExIS.IO.Tests/BExIS.IO.Tests.csproj +++ b/Components/IO/BExIS.IO.Tests/BExIS.IO.Tests.csproj @@ -57,7 +57,7 @@ ..\..\..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll - ..\..\..\packages\FluentAssertions.5.10.3\lib\net45\FluentAssertions.dll + ..\..\..\packages\FluentAssertions.5.10.3\lib\net47\FluentAssertions.dll ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll diff --git a/Components/IO/BExIS.IO.Tests/packages.config b/Components/IO/BExIS.IO.Tests/packages.config index 727e6a2652..d5b8b96436 100644 --- a/Components/IO/BExIS.IO.Tests/packages.config +++ b/Components/IO/BExIS.IO.Tests/packages.config @@ -2,6 +2,7 @@ + diff --git a/Components/IO/BExIS.IO.Transform.Input/BExIS.IO.Transform.Input.csproj b/Components/IO/BExIS.IO.Transform.Input/BExIS.IO.Transform.Input.csproj index 4daf2749b8..d43457e03a 100644 --- a/Components/IO/BExIS.IO.Transform.Input/BExIS.IO.Transform.Input.csproj +++ b/Components/IO/BExIS.IO.Transform.Input/BExIS.IO.Transform.Input.csproj @@ -56,7 +56,7 @@ ..\..\..\packages\F23.StringSimilarity.5.0.0\lib\netstandard2.0\F23.StringSimilarity.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/IO/BExIS.IO.Transform.Input/packages.config b/Components/IO/BExIS.IO.Transform.Input/packages.config index 01c8304722..45aa59a01d 100644 --- a/Components/IO/BExIS.IO.Transform.Input/packages.config +++ b/Components/IO/BExIS.IO.Transform.Input/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/Components/IO/BExIS.IO.Transform.Output/BExIS.IO.Transform.Output.csproj b/Components/IO/BExIS.IO.Transform.Output/BExIS.IO.Transform.Output.csproj index 89c6dc9626..029c863300 100644 --- a/Components/IO/BExIS.IO.Transform.Output/BExIS.IO.Transform.Output.csproj +++ b/Components/IO/BExIS.IO.Transform.Output/BExIS.IO.Transform.Output.csproj @@ -54,7 +54,7 @@ ..\..\..\Libraries\DocumentFormat.OpenXml.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/IO/BExIS.IO.Transform.Validation/BExIS.IO.Transform.Validation.csproj b/Components/IO/BExIS.IO.Transform.Validation/BExIS.IO.Transform.Validation.csproj index c762806b41..8a0d079bc4 100644 --- a/Components/IO/BExIS.IO.Transform.Validation/BExIS.IO.Transform.Validation.csproj +++ b/Components/IO/BExIS.IO.Transform.Validation/BExIS.IO.Transform.Validation.csproj @@ -87,6 +87,7 @@ + diff --git a/Components/IO/BExIS.IO.Transform.Validation/app.config b/Components/IO/BExIS.IO.Transform.Validation/app.config new file mode 100644 index 0000000000..16f3f079e6 --- /dev/null +++ b/Components/IO/BExIS.IO.Transform.Validation/app.config @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Components/IO/BExIS.IO/BExIS.IO.csproj b/Components/IO/BExIS.IO/BExIS.IO.csproj index 9372e6ba86..50af8adb7e 100644 --- a/Components/IO/BExIS.IO/BExIS.IO.csproj +++ b/Components/IO/BExIS.IO/BExIS.IO.csproj @@ -61,6 +61,7 @@ + diff --git a/Components/IO/BExIS.Io.Transform.Output/BExIS.Io.Transform.Output.csproj b/Components/IO/BExIS.Io.Transform.Output/BExIS.Io.Transform.Output.csproj index 89c6dc9626..029c863300 100644 --- a/Components/IO/BExIS.Io.Transform.Output/BExIS.Io.Transform.Output.csproj +++ b/Components/IO/BExIS.Io.Transform.Output/BExIS.Io.Transform.Output.csproj @@ -54,7 +54,7 @@ ..\..\..\Libraries\DocumentFormat.OpenXml.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/IO/BExIS.Io.Transform.Output/OutputMetadataManager.cs b/Components/IO/BExIS.Io.Transform.Output/OutputMetadataManager.cs index 8e5b8435af..2b025fd2a8 100644 --- a/Components/IO/BExIS.Io.Transform.Output/OutputMetadataManager.cs +++ b/Components/IO/BExIS.Io.Transform.Output/OutputMetadataManager.cs @@ -8,7 +8,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Xml; +using System.Xml.Linq; using Vaiona.Utils.Cfg; namespace BExIS.IO.Transform.Output @@ -103,6 +105,41 @@ public static XmlDocument GetConvertedMetadata(long datasetId, TransmissionType } } + public static string GetFlattenMetadata(XmlDocument metadata) + { + using (DatasetManager datasetManager = new DatasetManager()) + { + StringBuilder sb = new StringBuilder(); + + sb = flatten(sb, XElement.Parse(metadata.OuterXml)); + + return sb.ToString(); + } + } + + public static StringBuilder flatten(StringBuilder sb, XElement element, string currentPath = "") + { + // Construct the path: Parent/Child + string newPath = string.IsNullOrEmpty(currentPath) + ? element.Name.LocalName + : $"{currentPath}/{element.Name.LocalName}"; + + // If the element has no child elements, it's a leaf node—print the value + if (!element.Elements().Any()) + { + sb.AppendLine($"{newPath}:\t{element.Value.Trim()}"); + + } + + // Recurse through all child elements + foreach (var child in element.Elements()) + { + flatten(sb,child, newPath); + } + + return sb; + } + public static string GetSchemaDirectoryPath(long datasetId) { using (DatasetManager datasetManager = new DatasetManager()) diff --git a/Components/IO/BExIS.Io.Transform.Output/packages.config b/Components/IO/BExIS.Io.Transform.Output/packages.config index f50702e7f9..a2eabe2ead 100644 --- a/Components/IO/BExIS.Io.Transform.Output/packages.config +++ b/Components/IO/BExIS.Io.Transform.Output/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/Components/IO/BExIS.Io.Transform.Validation/BExIS.Io.Transform.Validation.csproj b/Components/IO/BExIS.Io.Transform.Validation/BExIS.Io.Transform.Validation.csproj index c762806b41..8a0d079bc4 100644 --- a/Components/IO/BExIS.Io.Transform.Validation/BExIS.Io.Transform.Validation.csproj +++ b/Components/IO/BExIS.Io.Transform.Validation/BExIS.Io.Transform.Validation.csproj @@ -87,6 +87,7 @@ + diff --git a/Components/IO/BExIS.Io/BExIS.Io.csproj b/Components/IO/BExIS.Io/BExIS.Io.csproj index 9372e6ba86..50af8adb7e 100644 --- a/Components/IO/BExIS.Io/BExIS.Io.csproj +++ b/Components/IO/BExIS.Io/BExIS.Io.csproj @@ -61,6 +61,7 @@ + diff --git a/Components/IO/BExIS.Io/IoHelper.cs b/Components/IO/BExIS.Io/IoHelper.cs index 942599e19b..345ce4ed12 100644 --- a/Components/IO/BExIS.Io/IoHelper.cs +++ b/Components/IO/BExIS.Io/IoHelper.cs @@ -35,7 +35,7 @@ public static string GetDynamicStoreFilePath(long datasetId, long datasetVersion return Path.Combine(storePath, fileName + extention); } - public static string GetFileName(FileType type, long datasetId, int versionNr, long datastructureId, string title = "") + public static string GetFileName(FileType type, long datasetId, int versionNr, long datastructureId, string title = "", double tagNr = 0, bool useTags = false, bool useMinor = false) { string appName = GeneralSettings.ApplicationName; if (string.IsNullOrEmpty(appName)) appName = "BEXIS2"; @@ -45,41 +45,42 @@ public static string GetFileName(FileType type, long datasetId, int versionNr, l string downloadTitle = FileNameUtility.SanitizeFileName(title,'-'); - + string versionOrTagLabel = useTags? "t"+tagNr : "v" + versionNr; // tag vs version? + // if tag active but not tag is set, t0 switch (type) { case FileType.Metadata: // filename should contain: application name, dataset ID, and version ID - downloadName = string.Format("{0}_{1}_v{2}_metadata", appName, datasetId, versionNr); + downloadName = string.Format("{0}_{1}_{2}_metadata", appName, datasetId, versionOrTagLabel); break; case FileType.MetadataExport: // filename should contain: application name, dataset ID, and version ID - downloadName = string.Format("{0}_{1}_v{2}_metadata_{3}", appName, datasetId, versionNr, title); + downloadName = string.Format("{0}_{1}_{2}_metadata_{3}", appName, datasetId, versionOrTagLabel, title); break; case FileType.DataStructure: downloadName = string.Format("{0}_{1}_data_structure_{2}", appName, datasetId, datastructureId); break; case FileType.PrimaryData: - downloadName = string.Format("{0}_{1}_v{2}_data", appName, datasetId, versionNr); + downloadName = string.Format("{0}_{1}_{2}_data", appName, datasetId, versionOrTagLabel); break; case FileType.PrimaryDataFiles: - downloadName = string.Format("{0}_{1}_v{2}_data_{3}", appName, datasetId, versionNr, title); + downloadName = string.Format("{0}_{1}_{2}_data_{3}", appName, datasetId, versionOrTagLabel, title); break; case FileType.Attachments: - downloadName = string.Format("{0}_{1}_v{2}_attachment_{3}", appName, datasetId, versionNr, title); + downloadName = string.Format("{0}_{1}_{2}_attachment_{3}", appName, datasetId, versionOrTagLabel, title); break; case FileType.Bundle: - downloadName = string.Format("{0}_{1}_v{2}_{3}_{4}", appName, datasetId, versionNr, downloadTitle, downloadDate); + downloadName = string.Format("{0}_{1}_{2}_{3}_{4}", appName, datasetId, versionOrTagLabel, downloadTitle, downloadDate); break; case FileType.Manifest: - downloadName = string.Format("{0}_{1}_v{2}_general_metadata", appName, datasetId, versionNr); + downloadName = string.Format("{0}_{1}_{2}_general_metadata", appName, datasetId, versionOrTagLabel); break; default: - downloadName = string.Format("{0}_{1}_v{2}_{3}", appName, datasetId, versionNr, title); + downloadName = string.Format("{0}_{1}_{2}_{3}", appName, datasetId, versionOrTagLabel, title); break; } diff --git a/Components/IO/BExIS.Io/app.config b/Components/IO/BExIS.Io/app.config index 1afcf4ca73..4838246c80 100644 --- a/Components/IO/BExIS.Io/app.config +++ b/Components/IO/BExIS.Io/app.config @@ -6,6 +6,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Components/JSON/BEXIS.JSON.Helpers/BEXIS.JSON.Helpers.csproj b/Components/JSON/BEXIS.JSON.Helpers/BEXIS.JSON.Helpers.csproj index d89b4cacc6..6d5ff49467 100644 --- a/Components/JSON/BEXIS.JSON.Helpers/BEXIS.JSON.Helpers.csproj +++ b/Components/JSON/BEXIS.JSON.Helpers/BEXIS.JSON.Helpers.csproj @@ -35,7 +35,7 @@ - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\Newtonsoft.Json.Schema.3.0.16\lib\net45\Newtonsoft.Json.Schema.dll diff --git a/Components/JSON/BEXIS.JSON.Helpers/MetadataStructureConverter.cs b/Components/JSON/BEXIS.JSON.Helpers/MetadataStructureConverter.cs index f495e7c3cb..bbd5374106 100644 --- a/Components/JSON/BEXIS.JSON.Helpers/MetadataStructureConverter.cs +++ b/Components/JSON/BEXIS.JSON.Helpers/MetadataStructureConverter.cs @@ -102,9 +102,37 @@ private JSchema addPackageUsage(MetadataPackageUsage usage, JSchema schema, out current = addMetadataAttrUsage(metadataAttrUsage, current, out _childRequired); // if current is required add it to the parent - if (_childRequired) current.Required.Add(metadataAttrUsage.Label); - if (IsChoice(usage.Extra) && getMaxCardinality(usage) > 1) current.AnyOf.Add(current.Properties.Last().Value); - else if (IsChoice(usage.Extra)) current.OneOf.Add(current.Properties.Last().Value); + //if (_childRequired) current.Required.Add(metadataAttrUsage.Label); + //if (IsChoice(usage.Extra) && getMaxCardinality(usage) > 1) current.AnyOf.Add(current.Properties.Last().Value); + //else if (IsChoice(usage.Extra)) current.OneOf.Add(current.Properties.Last().Value); + + var lastPropName = metadataAttrUsage.Label; // z.B. "Kreditkarte" + var lastPropSchema = current.Properties[lastPropName]; + + // falls das Kind für sich Required-Kinder hat, hast du das schon in lastPropSchema gesetzt + + if (IsChoice(usage.Extra)) + { + // Subschema für den Choice-Fall + var choiceSchema = new JSchema + { + Type = JSchemaType.Object + }; + + // gleiche Properties wie im Parent (damit die Validierung Sinn ergibt) + // minimal reicht i.d.R. das eine relevante Property: + choiceSchema.Properties.Add(lastPropName, lastPropSchema); + choiceSchema.Required.Add(lastPropName); + + if (getMaxCardinality(usage) > 1) + current.AnyOf.Add(choiceSchema); + else + current.OneOf.Add(choiceSchema); + } + else if (_childRequired) + { + current.Required.Add(lastPropName); + } } } @@ -217,10 +245,38 @@ private JSchema addMetadataAttrUsage(BaseUsage usage, JSchema schema, out bool r { bool _childIsRequired = false; current = addMetadataAttrUsage(mnau, current, out _childIsRequired); - // if current is required add it to the parent - if (_childIsRequired) current.Required.Add(mnau.Label); - if (IsChoice(usage.Extra) && getMaxCardinality(usage) > 1) current.AnyOf.Add(current.Properties.Last().Value); - else if (IsChoice(usage.Extra)) current.OneOf.Add(current.Properties.Last().Value); + //// if current is required add it to the parent + //if (_childIsRequired) current.Required.Add(mnau.Label); + //if (IsChoice(usage.Extra) && getMaxCardinality(usage) > 1) current.AnyOf.Add(current.Properties.Last().Value); + //else if (IsChoice(usage.Extra)) current.OneOf.Add(current.Properties.Last().Value); + + var lastPropName = mnau.Label; // z.B. "Kreditkarte" + var lastPropSchema = current.Properties[lastPropName]; + + // falls das Kind für sich Required-Kinder hat, hast du das schon in lastPropSchema gesetzt + + if (IsChoice(usage.Extra)) + { + // Subschema für den Choice-Fall + var choiceSchema = new JSchema + { + Type = JSchemaType.Object + }; + + // gleiche Properties wie im Parent (damit die Validierung Sinn ergibt) + // minimal reicht i.d.R. das eine relevante Property: + choiceSchema.Properties.Add(lastPropName, lastPropSchema); + choiceSchema.Required.Add(lastPropName); + + if (getMaxCardinality(usage) > 1) + current.AnyOf.Add(choiceSchema); + else + current.OneOf.Add(choiceSchema); + } + else if (_childIsRequired) + { + current.Required.Add(lastPropName); + } } } } @@ -343,6 +399,7 @@ private JSchema addConstraints(JSchema current, ICollection constrai if (constraint is DomainConstraint) { var d = (DomainConstraint)constraint; + if (!d.Items.Any()) d.Materialize(); d.Items.ForEach(i => current.Enum.Add(new JValue(i.Value))); } diff --git a/Components/JSON/BEXIS.JSON.Helpers/app.config b/Components/JSON/BEXIS.JSON.Helpers/app.config index 2f2071c802..4b7ae75a02 100644 --- a/Components/JSON/BEXIS.JSON.Helpers/app.config +++ b/Components/JSON/BEXIS.JSON.Helpers/app.config @@ -2,10 +2,6 @@ - - - - @@ -18,6 +14,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Components/JSON/BEXIS.JSON.Helpers/packages.config b/Components/JSON/BEXIS.JSON.Helpers/packages.config index 39d3c45d65..90b26cfd13 100644 --- a/Components/JSON/BEXIS.JSON.Helpers/packages.config +++ b/Components/JSON/BEXIS.JSON.Helpers/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/Components/JSON/BExIS.JSON.Helpers.Tests/BExIS.JSON.Helpers.Tests.csproj b/Components/JSON/BExIS.JSON.Helpers.Tests/BExIS.JSON.Helpers.Tests.csproj index b7925bf568..779a577a85 100644 --- a/Components/JSON/BExIS.JSON.Helpers.Tests/BExIS.JSON.Helpers.Tests.csproj +++ b/Components/JSON/BExIS.JSON.Helpers.Tests/BExIS.JSON.Helpers.Tests.csproj @@ -11,12 +11,13 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -24,6 +25,7 @@ + diff --git a/Components/JSON/BExIS.JSON.Helpers.Tests/app.config b/Components/JSON/BExIS.JSON.Helpers.Tests/app.config index 54a77950b0..47d362beb9 100644 --- a/Components/JSON/BExIS.JSON.Helpers.Tests/app.config +++ b/Components/JSON/BExIS.JSON.Helpers.Tests/app.config @@ -75,7 +75,7 @@ - + diff --git a/Components/UI/BExIS.UI.Tests/BExIS.UI.Tests.csproj b/Components/UI/BExIS.UI.Tests/BExIS.UI.Tests.csproj index 7ad7a67c66..8622efbfb6 100644 --- a/Components/UI/BExIS.UI.Tests/BExIS.UI.Tests.csproj +++ b/Components/UI/BExIS.UI.Tests/BExIS.UI.Tests.csproj @@ -53,10 +53,10 @@ ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll - ..\..\..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + ..\..\..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll - - ..\..\..\packages\FluentAssertions.5.1.2\lib\net47\FluentAssertions.dll + + ..\..\..\packages\FluentAssertions.5.10.3\lib\net47\FluentAssertions.dll ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll @@ -78,7 +78,7 @@ ..\..\..\packages\Moq.4.8.1\lib\net45\Moq.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\NHibernate.5.4.9\lib\net48\NHibernate.dll @@ -101,19 +101,19 @@ - - ..\..\..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + ..\..\..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll - - ..\..\..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + ..\..\..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - ..\..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + ..\..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll diff --git a/Components/UI/BExIS.UI.Tests/app.config b/Components/UI/BExIS.UI.Tests/app.config index 500c5fee25..1aef8935cd 100644 --- a/Components/UI/BExIS.UI.Tests/app.config +++ b/Components/UI/BExIS.UI.Tests/app.config @@ -133,7 +133,7 @@ - + @@ -157,12 +157,16 @@ - + + + + + diff --git a/Components/UI/BExIS.UI.Tests/packages.config b/Components/UI/BExIS.UI.Tests/packages.config index 44c57990c7..06f14a4989 100644 --- a/Components/UI/BExIS.UI.Tests/packages.config +++ b/Components/UI/BExIS.UI.Tests/packages.config @@ -1,13 +1,13 @@  - - + + - + @@ -16,9 +16,9 @@ - - - + + + \ No newline at end of file diff --git a/Components/UI/BExIS.UI/BExIS.UI.csproj b/Components/UI/BExIS.UI/BExIS.UI.csproj index 1b5719d2f8..061b5536ab 100644 --- a/Components/UI/BExIS.UI/BExIS.UI.csproj +++ b/Components/UI/BExIS.UI/BExIS.UI.csproj @@ -59,7 +59,7 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/UI/BExIS.UI/Hooks/Hook.cs b/Components/UI/BExIS.UI/Hooks/Hook.cs index 70d2feb98a..d26aadf373 100644 --- a/Components/UI/BExIS.UI/Hooks/Hook.cs +++ b/Components/UI/BExIS.UI/Hooks/Hook.cs @@ -87,10 +87,8 @@ protected bool hasUserEntityRights(long entityId, string userName, RightType rig { #region security permissions and authorisations check - using (EntityPermissionManager entityPermissionManager = new EntityPermissionManager()) - { - return entityPermissionManager.HasEffectiveRightsAsync(userName, typeof(Dataset), entityId, rightType).Result; - } + EntityPermissionManager entityPermissionManager = new EntityPermissionManager(); + return entityPermissionManager.HasEffectiveRightsAsync(userName, typeof(Dataset), entityId, rightType).Result; #endregion security permissions and authorisations check } diff --git a/Components/UI/BExIS.UI/packages.config b/Components/UI/BExIS.UI/packages.config index 5659c823ba..1472a6e275 100644 --- a/Components/UI/BExIS.UI/packages.config +++ b/Components/UI/BExIS.UI/packages.config @@ -6,7 +6,7 @@ - + \ No newline at end of file diff --git a/Components/Utils/BExIS.Utils.Config/BExIS.Utils.Config.csproj b/Components/Utils/BExIS.Utils.Config/BExIS.Utils.Config.csproj index 977ccdc3af..5a31b32f54 100644 --- a/Components/Utils/BExIS.Utils.Config/BExIS.Utils.Config.csproj +++ b/Components/Utils/BExIS.Utils.Config/BExIS.Utils.Config.csproj @@ -44,7 +44,7 @@ ..\..\..\packages\Microsoft.Owin.Security.OAuth.4.2.2\lib\net45\Microsoft.Owin.Security.OAuth.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll @@ -71,6 +71,7 @@ + diff --git a/Components/Utils/BExIS.Utils.Config/Configurations/JwtConfiguration.cs b/Components/Utils/BExIS.Utils.Config/Configurations/JwtConfiguration.cs index 78ca5f1f56..f36cf8ea3f 100644 --- a/Components/Utils/BExIS.Utils.Config/Configurations/JwtConfiguration.cs +++ b/Components/Utils/BExIS.Utils.Config/Configurations/JwtConfiguration.cs @@ -4,6 +4,9 @@ namespace BExIS.Utils.Config.Configurations { public class JwtConfiguration { + [JsonProperty("isActive")] + public bool IsActive { get; set; } + [JsonProperty("issuerSigningKey")] public string IssuerSigningKey { get; set; } diff --git a/Components/Utils/BExIS.Utils.Config/Configurations/SecurityConfiguration.cs b/Components/Utils/BExIS.Utils.Config/Configurations/SecurityConfiguration.cs new file mode 100644 index 0000000000..8454d62cbc --- /dev/null +++ b/Components/Utils/BExIS.Utils.Config/Configurations/SecurityConfiguration.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; + +namespace BExIS.Utils.Config.Configurations +{ + public class SecurityConfiguration + { + [JsonProperty("userValidatorConfiguration")] + public UserValidatorConfiguration UserValidatorConfiguration { get; set; } + + [JsonProperty("passwordValidatorConfiguration")] + public PasswordValidatorConfiguration PasswordValidatorConfiguration { get; set; } + } + + public class UserValidatorConfiguration + { + [JsonProperty("allowOnlyAlphanumericUserNames")] + public bool AllowOnlyAlphanumericUserNames { get; set; } + + [JsonProperty("requireUniqueEmail")] + public bool RequireUniqueEmail { get; set; } + } + + public class PasswordValidatorConfiguration + { + [JsonProperty("requiredLength")] + public int RequiredLength { get; set; } + + [JsonProperty("requireNonLetterOrDigit")] + public bool RequireNonLetterOrDigit { get; set; } + + [JsonProperty("requireDigit")] + public bool RequireDigit { get; set; } + + [JsonProperty("requireLowercase")] + public bool RequireLowercase { get; set; } + + [JsonProperty("requireUppercase")] + public bool RequireUppercase { get; set; } + } +} diff --git a/Components/Utils/BExIS.Utils.Config/Configurations/SmtpConfiguration.cs b/Components/Utils/BExIS.Utils.Config/Configurations/SmtpConfiguration.cs index d68f34ec8d..0a5b84ec6a 100644 --- a/Components/Utils/BExIS.Utils.Config/Configurations/SmtpConfiguration.cs +++ b/Components/Utils/BExIS.Utils.Config/Configurations/SmtpConfiguration.cs @@ -4,6 +4,9 @@ namespace BExIS.Utils.Config.Configurations { public class SmtpConfiguration { + [JsonProperty("isActive")] + public bool IsActive { get; set; } + [JsonProperty("hostName")] public string HostName { get; set; } diff --git a/Components/Utils/BExIS.Utils.Config/GeneralSettings.cs b/Components/Utils/BExIS.Utils.Config/GeneralSettings.cs index 394b300008..738e0c88fa 100644 --- a/Components/Utils/BExIS.Utils.Config/GeneralSettings.cs +++ b/Components/Utils/BExIS.Utils.Config/GeneralSettings.cs @@ -1,10 +1,15 @@ using BExIS.Utils.Config.Configurations; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using System.Text; +using System.Web.Http.Results; using Vaiona.IoC; using Vaiona.Utils.Cfg; @@ -38,6 +43,18 @@ public string GetApplicationName() } } + public SecurityConfiguration GetSecurityConfiguration() + { + try + { + return GetValueByKey("security"); + } + catch (Exception ex) + { + return new SecurityConfiguration(); + } + } + public JwtConfiguration GetJwtConfiguration() { try @@ -124,11 +141,95 @@ public static string FAQ } } + public static SecurityConfiguration SecurityConfiguration + { + get + { + var json = GetValueByKey("security")?.ToString(); + + if (string.IsNullOrWhiteSpace(json)) + return new SecurityConfiguration(); + + try + { + var config = JsonConvert.DeserializeObject(json); + return config ?? new SecurityConfiguration(); + } + catch (JsonException ex) + { + + return new SecurityConfiguration(); + } + } + } + public static JwtConfiguration JwtConfiguration { get { - return JsonConvert.DeserializeObject(GetValueByKey("jwt").ToString()); + var json = GetValueByKey("jwt")?.ToString(); + + if (string.IsNullOrWhiteSpace(json)) + return new JwtConfiguration(); + + try + { + var config = JsonConvert.DeserializeObject(json); + return config ?? new JwtConfiguration() { IsActive = false }; + } + catch (JsonException ex) + { + return new JwtConfiguration() { IsActive = false }; + } + } + } + + public static bool CreateIssuerSigningKey() + { + GeneralSettings settings = Get(); + JsonSettings jsonSettings = settings.GetAsJsonModel(); + + // Finde den Eintrag mit key = "jwt" + var jwtEntry = jsonSettings.Entries.FirstOrDefault(e => e.Key == "jwt"); + if (jwtEntry == null) + throw new InvalidOperationException("Kein Eintrag mit key='jwt' gefunden."); + + // Annahme: jwtEntry.Value ist ein JObject + if (jwtEntry.Value is JObject jwtValueObj) + { + // Ändere den Wert direkt im Objekt + jwtValueObj["issuerSigningKey"] = generateRandomAlphanumericString(48); + } + else + { + throw new InvalidOperationException("Der Wert von 'jwt' ist kein JObject."); + } + + // Speichere zurück + settings.Update(jsonSettings); + + return true; + } + + private static string generateRandomAlphanumericString(int length = 48) + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + using (var rng = RandomNumberGenerator.Create()) + { + var result = new StringBuilder(length); + var buffer = new byte[16]; // Genügend für mehrere Zeichen + + while (result.Length < length) + { + rng.GetBytes(buffer); + for (int i = 0; i < buffer.Length && result.Length < length; i++) + { + // Nutze den Wert als Index in den Zeichen + result.Append(chars[buffer[i] % chars.Length]); + } + } + + return result.ToString(); } } @@ -136,7 +237,20 @@ public static SmtpConfiguration SmtpConfiguration { get { - return JsonConvert.DeserializeObject(GetValueByKey("smtp").ToString()); + var json = GetValueByKey("smtp")?.ToString(); + + if (string.IsNullOrWhiteSpace(json)) + return new SmtpConfiguration() { IsActive = false }; + + try + { + var config = JsonConvert.DeserializeObject(json); + return config ?? new SmtpConfiguration() { IsActive = false }; + } + catch (JsonException ex) + { + return new SmtpConfiguration() { IsActive = false }; + } } } @@ -144,7 +258,21 @@ public static ExceptionConfiguration ExceptionConfiguration { get { - return JsonConvert.DeserializeObject(GetValueByKey("exception").ToString()); + var json = GetValueByKey("exception")?.ToString(); + + if (string.IsNullOrWhiteSpace(json)) + return new ExceptionConfiguration(); // leere Instanz mit Defaults + + try + { + var config = JsonConvert.DeserializeObject(json); + return config ?? new ExceptionConfiguration(); + } + catch (JsonException ex) + { + // Logger.Error($"Fehler beim Deserialisieren der SecurityConfiguration: {ex.Message}"); + return new ExceptionConfiguration(); // Fallback auf Defaults + } } } diff --git a/Components/Utils/BExIS.Utils.Config/packages.config b/Components/Utils/BExIS.Utils.Config/packages.config index 88e6453c5a..b0101fc777 100644 --- a/Components/Utils/BExIS.Utils.Config/packages.config +++ b/Components/Utils/BExIS.Utils.Config/packages.config @@ -7,7 +7,7 @@ - + \ No newline at end of file diff --git a/Components/Utils/BExIS.Utils.Data.Tests/BExIS.Utils.Data.Tests.csproj b/Components/Utils/BExIS.Utils.Data.Tests/BExIS.Utils.Data.Tests.csproj index 8791780c7d..34c500fc9b 100644 --- a/Components/Utils/BExIS.Utils.Data.Tests/BExIS.Utils.Data.Tests.csproj +++ b/Components/Utils/BExIS.Utils.Data.Tests/BExIS.Utils.Data.Tests.csproj @@ -74,7 +74,7 @@ ..\..\..\packages\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\NHibernate.5.4.9\lib\net48\NHibernate.dll diff --git a/Components/Utils/BExIS.Utils.Data.Tests/packages.config b/Components/Utils/BExIS.Utils.Data.Tests/packages.config index 84c9141b66..d2ba1c2221 100644 --- a/Components/Utils/BExIS.Utils.Data.Tests/packages.config +++ b/Components/Utils/BExIS.Utils.Data.Tests/packages.config @@ -7,7 +7,7 @@ - + diff --git a/Components/Utils/BExIS.Utils.Data/BExIS.Utils.Data.csproj b/Components/Utils/BExIS.Utils.Data/BExIS.Utils.Data.csproj index b8291b9234..7e9cc797ed 100644 --- a/Components/Utils/BExIS.Utils.Data/BExIS.Utils.Data.csproj +++ b/Components/Utils/BExIS.Utils.Data/BExIS.Utils.Data.csproj @@ -41,28 +41,28 @@ prompt - - ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + ..\..\..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.Helpers.dll ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.9\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.WebPages.Razor.dll diff --git a/Components/Utils/BExIS.Utils.Data/DatasetVersionHelper.cs b/Components/Utils/BExIS.Utils.Data/DatasetVersionHelper.cs index d588735622..063d1538b7 100644 --- a/Components/Utils/BExIS.Utils.Data/DatasetVersionHelper.cs +++ b/Components/Utils/BExIS.Utils.Data/DatasetVersionHelper.cs @@ -17,9 +17,9 @@ public static async Task GetVersionId(long datasetId, string username, int bool isVerionReady = false; - using (var permissionManager = new EntityPermissionManager()) using (var datasetManager = new DatasetManager()) { + var permissionManager = new EntityPermissionManager(); var dataset = datasetManager.GetDataset(datasetId); diff --git a/Components/Utils/BExIS.Utils.Data/Helpers/ShellSeedDataGenerator.cs b/Components/Utils/BExIS.Utils.Data/Helpers/ShellSeedDataGenerator.cs index 019254f8f1..a400b6ddcb 100644 --- a/Components/Utils/BExIS.Utils.Data/Helpers/ShellSeedDataGenerator.cs +++ b/Components/Utils/BExIS.Utils.Data/Helpers/ShellSeedDataGenerator.cs @@ -16,8 +16,8 @@ public void GenerateSeedData() // Features using (var featureManager = new FeatureManager()) using (var operationManager = new OperationManager()) - using (var versionManager = new VersionManager()) { + var versionManager = new VersionManager(); var bexisFeature = featureManager.FindByName("BExIS") ?? featureManager.Create("BExIS", "This is the root!"); var settings = featureManager.FindByName("Settings") ?? featureManager.Create("Settings", "This is the settings page!", bexisFeature); @@ -40,9 +40,9 @@ public void GenerateSeedData() var o12 = operationManager.Find("Shell", "Settings", "*") ?? operationManager.Create("Shell", "Settings", "*", settings); - if (!versionManager.Exists("Shell", "4.2.1")) + if (!versionManager.Exists("Shell", "4.3.0")) { - versionManager.Create("Shell", "4.2.1"); + versionManager.Create("Shell", "4.3.0"); } } } diff --git a/Components/Utils/BExIS.Utils.Data/packages.config b/Components/Utils/BExIS.Utils.Data/packages.config index 6813cae0ec..b94c99c2d4 100644 --- a/Components/Utils/BExIS.Utils.Data/packages.config +++ b/Components/Utils/BExIS.Utils.Data/packages.config @@ -1,8 +1,8 @@  - - + + - + \ No newline at end of file diff --git a/Components/Utils/BExIS.Utils.Tests/BExIS.Utils.Tests.csproj b/Components/Utils/BExIS.Utils.Tests/BExIS.Utils.Tests.csproj index 1495ffc90a..6e37cd4a8c 100644 --- a/Components/Utils/BExIS.Utils.Tests/BExIS.Utils.Tests.csproj +++ b/Components/Utils/BExIS.Utils.Tests/BExIS.Utils.Tests.csproj @@ -52,9 +52,6 @@ ..\..\..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll - - ..\..\..\packages\FluentAssertions.5.10.3\lib\net45\FluentAssertions.dll - ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll True @@ -70,7 +67,7 @@ ..\..\..\packages\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\NHibernate.5.4.9\lib\net48\NHibernate.dll diff --git a/Components/Utils/BExIS.Utils.Tests/packages.config b/Components/Utils/BExIS.Utils.Tests/packages.config index a77acb07fb..c795f9b0e4 100644 --- a/Components/Utils/BExIS.Utils.Tests/packages.config +++ b/Components/Utils/BExIS.Utils.Tests/packages.config @@ -2,12 +2,11 @@ - - + diff --git a/Components/Utils/BExIS.Utils/BExIS.Utils.csproj b/Components/Utils/BExIS.Utils/BExIS.Utils.csproj index 8825eb75e2..c12e497dff 100644 --- a/Components/Utils/BExIS.Utils/BExIS.Utils.csproj +++ b/Components/Utils/BExIS.Utils/BExIS.Utils.csproj @@ -97,6 +97,7 @@ + diff --git a/Components/Utils/BExIS.Utils/Extensions/IdentityExtensions.cs b/Components/Utils/BExIS.Utils/Extensions/IdentityExtensions.cs new file mode 100644 index 0000000000..d0536dfabe --- /dev/null +++ b/Components/Utils/BExIS.Utils/Extensions/IdentityExtensions.cs @@ -0,0 +1,24 @@ +using BExIS.Security.Entities.Subjects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace BExIS.Utils.Extensions +{ + public static class IdentityExtensions + { + public static string GetDisplayName(this IIdentity identity) + { + // Hier kannst du eigene Logik implementieren + // Beispiel: Casting auf eine konkrete User-Klasse, um Zugriff auf eigene Eigenschaften + if (identity is User user) + { + return $"{user.DisplayName ?? user.Name}"; + } + return "unknown"; + } + } +} diff --git a/Components/Vaiona/Vaiona.Utils/Vaiona.Utils.csproj b/Components/Vaiona/Vaiona.Utils/Vaiona.Utils.csproj index 3f526d62da..9fa1659d74 100644 --- a/Components/Vaiona/Vaiona.Utils/Vaiona.Utils.csproj +++ b/Components/Vaiona/Vaiona.Utils/Vaiona.Utils.csproj @@ -35,7 +35,7 @@ - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/Vaiona/Vaiona.Utils/packages.config b/Components/Vaiona/Vaiona.Utils/packages.config index 0b14af3ad0..8f8cd00621 100644 --- a/Components/Vaiona/Vaiona.Utils/packages.config +++ b/Components/Vaiona/Vaiona.Utils/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/Components/Vaiona/Vaiona.Web.Mvc.Modularity/Vaiona.Web.Mvc.Modularity.csproj b/Components/Vaiona/Vaiona.Web.Mvc.Modularity/Vaiona.Web.Mvc.Modularity.csproj index 99cd53714a..a5cf95eaa2 100644 --- a/Components/Vaiona/Vaiona.Web.Mvc.Modularity/Vaiona.Web.Mvc.Modularity.csproj +++ b/Components/Vaiona/Vaiona.Web.Mvc.Modularity/Vaiona.Web.Mvc.Modularity.csproj @@ -38,7 +38,7 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/Vaiona/Vaiona.Web.Mvc.Modularity/packages.config b/Components/Vaiona/Vaiona.Web.Mvc.Modularity/packages.config index f17444e2b8..a5d93f25f1 100644 --- a/Components/Vaiona/Vaiona.Web.Mvc.Modularity/packages.config +++ b/Components/Vaiona/Vaiona.Web.Mvc.Modularity/packages.config @@ -6,5 +6,5 @@ - + \ No newline at end of file diff --git a/Components/Vaiona/Vaiona.Web.Mvc/Vaiona.Web.Mvc.csproj b/Components/Vaiona/Vaiona.Web.Mvc/Vaiona.Web.Mvc.csproj index 1c61d8ac1d..56696252df 100644 --- a/Components/Vaiona/Vaiona.Web.Mvc/Vaiona.Web.Mvc.csproj +++ b/Components/Vaiona/Vaiona.Web.Mvc/Vaiona.Web.Mvc.csproj @@ -41,7 +41,7 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\Newtonsoft.Json.Bson.1.0.2\lib\net45\Newtonsoft.Json.Bson.dll diff --git a/Components/Vaiona/Vaiona.Web.Mvc/packages.config b/Components/Vaiona/Vaiona.Web.Mvc/packages.config index a891c9bde4..6650f975e5 100644 --- a/Components/Vaiona/Vaiona.Web.Mvc/packages.config +++ b/Components/Vaiona/Vaiona.Web.Mvc/packages.config @@ -6,7 +6,7 @@ - + diff --git a/Components/XML/BExIS.Xml.Helpers.UnitTests/BExIS.Xml.Helpers.UnitTests.csproj b/Components/XML/BExIS.Xml.Helpers.UnitTests/BExIS.Xml.Helpers.UnitTests.csproj index 69a8b19e0b..ce2d0fa95e 100644 --- a/Components/XML/BExIS.Xml.Helpers.UnitTests/BExIS.Xml.Helpers.UnitTests.csproj +++ b/Components/XML/BExIS.Xml.Helpers.UnitTests/BExIS.Xml.Helpers.UnitTests.csproj @@ -71,7 +71,7 @@ ..\..\..\packages\Moq.4.8.1\lib\net45\Moq.dll - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll ..\..\..\packages\Newtonsoft.Json.Schema.3.0.16\lib\net45\Newtonsoft.Json.Schema.dll diff --git a/Components/XML/BExIS.Xml.Helpers.UnitTests/XmlMetadataConverterTests.cs b/Components/XML/BExIS.Xml.Helpers.UnitTests/XmlMetadataConverterTests.cs index f6d116ccca..2c490dc3bb 100644 --- a/Components/XML/BExIS.Xml.Helpers.UnitTests/XmlMetadataConverterTests.cs +++ b/Components/XML/BExIS.Xml.Helpers.UnitTests/XmlMetadataConverterTests.cs @@ -64,7 +64,9 @@ public void ConvertTo_XmlToJson_ReturnJson() JObject result = xmlMetadataHelper.ConvertTo(xmlDocument); JObject result2 = xmlMetadataHelper.ConvertTo(xmlDocument, true); - bool isvalid = result.IsValid(schema); + IList errorMessages = new List(); + + bool isvalid = result.IsValid(schema, out errorMessages); var json = JsonConvert.SerializeObject(result); var json2 = JsonConvert.SerializeObject(result2); diff --git a/Components/XML/BExIS.Xml.Helpers.UnitTests/packages.config b/Components/XML/BExIS.Xml.Helpers.UnitTests/packages.config index e5139ba9b4..d757e5df9a 100644 --- a/Components/XML/BExIS.Xml.Helpers.UnitTests/packages.config +++ b/Components/XML/BExIS.Xml.Helpers.UnitTests/packages.config @@ -7,7 +7,7 @@ - + diff --git a/Components/XML/BExIS.Xml.Helpers/BExIS.Xml.Helpers.csproj b/Components/XML/BExIS.Xml.Helpers/BExIS.Xml.Helpers.csproj index cf26493387..bd80f6d530 100644 --- a/Components/XML/BExIS.Xml.Helpers/BExIS.Xml.Helpers.csproj +++ b/Components/XML/BExIS.Xml.Helpers/BExIS.Xml.Helpers.csproj @@ -50,7 +50,7 @@ - ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/Components/XML/BExIS.Xml.Helpers/XmlMetadataConverter.cs b/Components/XML/BExIS.Xml.Helpers/XmlMetadataConverter.cs index 5a94b8c08e..626b18b5f4 100644 --- a/Components/XML/BExIS.Xml.Helpers/XmlMetadataConverter.cs +++ b/Components/XML/BExIS.Xml.Helpers/XmlMetadataConverter.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; using System.Xml; using System.Xml.Linq; @@ -122,7 +123,8 @@ private JToken _convertPackageUsage(XmlNode node, MetadataPackageUsage usage, bo // complex stuff // add all children nodes JObject complex = new JObject(); - setReference(complex, (XmlElement)tCHild, includeEmpty); + //setReference(complex, (XmlElement)tCHild, includeEmpty); + //setParameters(complex, (XmlElement)tCHild, includeEmpty); for (int i = 0; i < tCHild.ChildNodes.Count; i++) { @@ -142,6 +144,13 @@ private JToken _convertPackageUsage(XmlNode node, MetadataPackageUsage usage, bo } if (!complex.Children().Any()) return null; + else + { + setReference(complex, (XmlElement)tCHild, includeEmpty); + setParameters(complex, (XmlElement)tCHild, includeEmpty); + + } + if (getMaxCardinality(usage) <= 1) return complex; else @@ -216,8 +225,7 @@ private JToken _convertElementUsage(XmlNode node, BaseUsage usage, bool includeE // complex stuff // add all children nodes JObject complex = new JObject(); - setReference(complex, (XmlElement)tCHild, includeEmpty); - + for (int i = 0; i < tCHild.ChildNodes.Count; i++) { XmlNode child = tCHild.ChildNodes[i]; @@ -239,6 +247,13 @@ private JToken _convertElementUsage(XmlNode node, BaseUsage usage, bool includeE } if (!complex.Children().Any()) return null; + else + { + setReference(complex, (XmlElement)tCHild, includeEmpty); + setParameters(complex, (XmlElement)tCHild, includeEmpty); + + } + if (getMaxCardinality(usage) <= 1) return complex; else @@ -324,6 +339,7 @@ private JObject addSimple(BaseUsage usage, string valueAsString, XmlElement refe } setReference(simple, reference, includeEmpty); + setParameters(simple, reference, includeEmpty); simple.Add(new JProperty("#text", value)); @@ -351,6 +367,22 @@ private void setReference(JObject target, XmlElement element, bool includeEmpty) } } + private void setParameters(JObject target, XmlElement element, bool includeEmpty) + { + if(element.HasAttributes) + { + List ignore = new List() { "type", "ref", "id", "roleId", "number", "name","partyid" }; // system attributes + + foreach (XmlAttribute attr in element.Attributes) + { + if (!ignore.Contains(attr.Name)) + { + target.Add("@" + attr.Name, attr.Value); + } + } + } + } + #endregion XML to JSON #region JSON to XML @@ -623,7 +655,7 @@ public bool HasValidStructure(JObject metadataJson, long metadataStructureId, ou // load example xml based on metadata structure var xmlMetadatWriter = new XmlMetadataWriter(BExIS.Xml.Helpers.XmlNodeMode.xPath); - var metadataExample = xmlMetadatWriter.CreateMetadataXml(metadataStructureId); + var metadataExample = xmlMetadatWriter.CreateTempMetadataXmlWithChoiceChildrens(metadataStructureId); // get all elements from xml documents to compare var listOfElementsInput = XmlUtility.GetAllChildren(XmlUtility.ToXDocument(metadataInput).Root).Select(e => e.Name.LocalName); diff --git a/Components/XML/BExIS.Xml.Helpers/XmlMetadataWriter.cs b/Components/XML/BExIS.Xml.Helpers/XmlMetadataWriter.cs index 7b1eac5af7..56473d8754 100644 --- a/Components/XML/BExIS.Xml.Helpers/XmlMetadataWriter.cs +++ b/Components/XML/BExIS.Xml.Helpers/XmlMetadataWriter.cs @@ -160,7 +160,7 @@ public XDocument CreateTempMetadataXmlWithChoiceChildrens(long metadataStructure package.SetAttributeValue("number", "1"); role.Add(package); - setChildren(package, mpu); + setChildren(package, mpu, null, true); } return doc; @@ -177,7 +177,7 @@ private bool IsChoice(XmlNode xmlNode) return false; } - private XElement setChildren(XElement element, BaseUsage usage, XDocument importDocument = null) + private XElement setChildren(XElement element, BaseUsage usage, XDocument importDocument = null, bool withChoiceChildren = false ) { MetadataAttribute metadataAttribute = null; MetadataPackage metadataPackage = null; @@ -235,7 +235,7 @@ private XElement setChildren(XElement element, BaseUsage usage, XDocument import foreach (var type in typeList) { - setChildren(type, nestedUsage, importDocument); + setChildren(type, nestedUsage, importDocument, withChoiceChildren); } } else @@ -245,7 +245,7 @@ private XElement setChildren(XElement element, BaseUsage usage, XDocument import typeList = addAndReturnAttribute(element, nestedUsage, 1, 1); if (nestedUsage.Extra == null || !IsChoice(nestedUsage.Extra)) - setChildren(typeList.FirstOrDefault(), nestedUsage, importDocument); + setChildren(typeList.FirstOrDefault(), nestedUsage, importDocument, withChoiceChildren); } } } @@ -286,7 +286,7 @@ private XElement setChildren(XElement element, BaseUsage usage, XDocument import foreach (var type in typeList) { - setChildren(type, attrUsage, importDocument); + setChildren(type, attrUsage, importDocument, withChoiceChildren); } } else @@ -295,8 +295,8 @@ private XElement setChildren(XElement element, BaseUsage usage, XDocument import typeList = addAndReturnAttribute(element, attrUsage, 1, 1); - if (attrUsage.Extra == null || !IsChoice(attrUsage.Extra)) - setChildren(typeList.FirstOrDefault(), attrUsage, importDocument); + if (attrUsage.Extra == null || (!IsChoice(attrUsage.Extra)|| withChoiceChildren)) + setChildren(typeList.FirstOrDefault(), attrUsage, importDocument, withChoiceChildren); } } } diff --git a/Components/XML/BExIS.Xml.Helpers/packages.config b/Components/XML/BExIS.Xml.Helpers/packages.config index 2150347e7e..f882203c48 100644 --- a/Components/XML/BExIS.Xml.Helpers/packages.config +++ b/Components/XML/BExIS.Xml.Helpers/packages.config @@ -5,7 +5,7 @@ - + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell.Svelte/package-lock.json b/Console/BExIS.Web.Shell.Svelte/package-lock.json index 0971161e8c..ca61d134dc 100644 --- a/Console/BExIS.Web.Shell.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell.Svelte/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "hasInstallScript": true, "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.64", + "@bexis2/bexis2-core-ui": "0.4.75", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", @@ -76,9 +76,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.63", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.63.tgz", - "integrity": "sha512-tLqUzCsCslNSA+YoMd6+FRA6SXY2SOet9RVdQbe6khVXEc33lvFwu3ZrNfNBT3Ku5ca1dtngzA4dhSNeCAg99A==", + "version": "0.4.74", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.74.tgz", + "integrity": "sha512-RGtbDZRDIICzcm7b2b7p8GFrbYlg3CBDDLqNytGO7schfa1Kb6N1MgSmE6Mwqb3hkgTYSVfD9vCwIlp9s1MvWQ==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", @@ -245,6 +245,358 @@ "w3c-keyname": "^2.2.4" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/win32-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", @@ -701,6 +1053,240 @@ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", + "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", + "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", + "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", + "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", + "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", + "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", + "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", + "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", + "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", + "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", + "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", + "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", + "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", + "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", + "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", + "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", + "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", + "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.34.8", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", @@ -759,6 +1345,7 @@ "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.19.tgz", "integrity": "sha512-r/lah3nnYEZX1btlvpSy+Exkt1aWhmOP5pnCt+BBro+tZrh2Zci+26Xnm1fCBLLMeM5q7gHvWiS8c/UtrWjdvQ==", "hasInstallScript": true, + "peer": true, "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", @@ -789,6 +1376,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", + "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", "debug": "^4.3.4", @@ -864,6 +1452,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.2.tgz", "integrity": "sha512-yPL6DyFwY5PiMVEwymNeqUTKsDczQBJ/5T7W/46RwLU/VH+AA8aT5TZkvBviLKLbbm0hlfftEkGrNzfRk/fofQ==", "devOptional": true, + "peer": true, "dependencies": { "undici-types": "~6.11.1" } @@ -912,6 +1501,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0.tgz", "integrity": "sha512-pS1hdZ+vnrpDIxuFXYQpLTILglTjSYJ9MbetZctrUawogUsPdz31DIIRZ9+rab0LhYNTsk88w4fIzVheiTbWOQ==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.0.0", "@typescript-eslint/types": "8.0.0", @@ -1170,6 +1760,7 @@ "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1425,6 +2016,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -1667,6 +2259,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "peer": true, "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", @@ -2114,6 +2707,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", "integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", @@ -2582,6 +3176,20 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3901,6 +4509,21 @@ "node": ">=18" } }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.4.40", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", @@ -3919,6 +4542,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.1", @@ -3979,6 +4603,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" @@ -4082,6 +4707,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -4656,6 +5282,7 @@ "version": "4.2.18", "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.18.tgz", "integrity": "sha512-d0FdzYIiAePqRJEb90WlJDkjUEx42xhivxN8muUBmfZnP+tzUgz12DJ2hRJi8sIHCME7jeK1PTMgKPSfTd8JrA==", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", @@ -4872,6 +5499,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.7.tgz", "integrity": "sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==", "dev": true, + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -5056,6 +5684,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5161,6 +5790,7 @@ "version": "5.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.5.tgz", "integrity": "sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.39", diff --git a/Console/BExIS.Web.Shell.Svelte/package.json b/Console/BExIS.Web.Shell.Svelte/package.json index 4f43fac141..012ccc8f7c 100644 --- a/Console/BExIS.Web.Shell.Svelte/package.json +++ b/Console/BExIS.Web.Shell.Svelte/package.json @@ -52,7 +52,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.65", + "@bexis2/bexis2-core-ui": "0.4.75", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", diff --git a/Console/BExIS.Web.Shell.Svelte/src/components/entry.svelte b/Console/BExIS.Web.Shell.Svelte/src/components/entry.svelte index 75f7825c78..a9d376cac3 100644 --- a/Console/BExIS.Web.Shell.Svelte/src/components/entry.svelte +++ b/Console/BExIS.Web.Shell.Svelte/src/components/entry.svelte @@ -62,7 +62,7 @@
helpStore.show(entry.key)}>