Merge pull request 'Blazorise' (#4) from Blazorise into main
Reviewed-on: #4
This commit was merged in pull request #4.
	This commit is contained in:
		
							
								
								
									
										4
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					[*.cs]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CA1822: Member als statisch markieren
 | 
				
			||||||
 | 
					dotnet_diagnostic.CA1822.severity = suggestion
 | 
				
			||||||
							
								
								
									
										8
									
								
								.idea/.idea.UserService/.idea/indexLayout.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/.idea.UserService/.idea/indexLayout.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project version="4">
 | 
				
			||||||
 | 
					  <component name="ContentModelUserStore">
 | 
				
			||||||
 | 
					    <attachedFolders />
 | 
				
			||||||
 | 
					    <explicitIncludes />
 | 
				
			||||||
 | 
					    <explicitExcludes />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										8
									
								
								.idea/.idea.UserService/.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/.idea.UserService/.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project version="4">
 | 
				
			||||||
 | 
					  <component name="ProjectModuleManager">
 | 
				
			||||||
 | 
					    <modules>
 | 
				
			||||||
 | 
					      <module fileurl="file://$PROJECT_DIR$/.idea/.idea.UserService/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.UserService/riderModule.iml" />
 | 
				
			||||||
 | 
					    </modules>
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										6
									
								
								.idea/.idea.UserService/.idea/projectSettingsUpdater.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/.idea.UserService/.idea/projectSettingsUpdater.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project version="4">
 | 
				
			||||||
 | 
					  <component name="RiderProjectSettingsUpdater">
 | 
				
			||||||
 | 
					    <option name="vcsConfiguration" value="2" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										6
									
								
								.idea/.idea.UserService/.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/.idea.UserService/.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project version="4">
 | 
				
			||||||
 | 
					  <component name="VcsDirectoryMappings">
 | 
				
			||||||
 | 
					    <mapping directory="$PROJECT_DIR$" vcs="Git" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										15
									
								
								.idea/.idea.UserService/riderModule.iml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								.idea/.idea.UserService/riderModule.iml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<module type="RIDER_MODULE" version="4">
 | 
				
			||||||
 | 
					  <component name="NewModuleRootManager">
 | 
				
			||||||
 | 
					    <content url="file://$USER_HOME$/.nuget/packages/microsoft.net.test.sdk/16.7.0/build/netcoreapp2.1" />
 | 
				
			||||||
 | 
					    <content url="file://$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.7.0/build/netcoreapp2.1/x64/testhost.dll" />
 | 
				
			||||||
 | 
					    <content url="file://$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.7.0/build/netcoreapp2.1/x64/testhost.exe" />
 | 
				
			||||||
 | 
					    <content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.17.0/build/netcoreapp2.1/NUnit3.TestAdapter.dll" />
 | 
				
			||||||
 | 
					    <content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.17.0/build/netcoreapp2.1/NUnit3.TestAdapter.pdb" />
 | 
				
			||||||
 | 
					    <content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.17.0/build/netcoreapp2.1/nunit.engine.api.dll" />
 | 
				
			||||||
 | 
					    <content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.17.0/build/netcoreapp2.1/nunit.engine.core.dll" />
 | 
				
			||||||
 | 
					    <content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.17.0/build/netcoreapp2.1/nunit.engine.dll" />
 | 
				
			||||||
 | 
					    <content url="file://$MODULE_DIR$/../.." />
 | 
				
			||||||
 | 
					    <orderEntry type="sourceFolder" forTests="false" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</module>
 | 
				
			||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
using Microsoft.EntityFrameworkCore;
 | 
					using System;
 | 
				
			||||||
 | 
					using Microsoft.EntityFrameworkCore;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace UserService.DatabaseLayer.DataModels
 | 
					namespace UserService.DatabaseLayer.DataModels
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -7,6 +9,7 @@ namespace UserService.DatabaseLayer.DataModels
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public static void Seed(this ModelBuilder modelBuilder)
 | 
					        public static void Seed(this ModelBuilder modelBuilder)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if (modelBuilder == null) throw new ArgumentNullException(nameof(modelBuilder));
 | 
				
			||||||
            var groups = new OrganizationUnit { CommonName = "Groups", Id = -1 };
 | 
					            var groups = new OrganizationUnit { CommonName = "Groups", Id = -1 };
 | 
				
			||||||
            var users = new OrganizationUnit { CommonName = "Users", Id = -2 };
 | 
					            var users = new OrganizationUnit { CommonName = "Users", Id = -2 };
 | 
				
			||||||
            var germany = new OrganizationUnit{CommonName = "Germany", Id = -6, ParentId = -2};
 | 
					            var germany = new OrganizationUnit{CommonName = "Germany", Id = -6, ParentId = -2};
 | 
				
			||||||
@@ -14,7 +17,7 @@ namespace UserService.DatabaseLayer.DataModels
 | 
				
			|||||||
            var arizona = new OrganizationUnit{CommonName = "Arizona" , Id = -4, ParentId = -5 };
 | 
					            var arizona = new OrganizationUnit{CommonName = "Arizona" , Id = -4, ParentId = -5 };
 | 
				
			||||||
            var france = new OrganizationUnit{CommonName = "France" , Id = -3, ParentId = -2 };
 | 
					            var france = new OrganizationUnit{CommonName = "France" , Id = -3, ParentId = -2 };
 | 
				
			||||||
            modelBuilder.Entity<OrganizationUnit>().HasData(users, groups, germany, usa, arizona, france);
 | 
					            modelBuilder.Entity<OrganizationUnit>().HasData(users, groups, germany, usa, arizona, france);
 | 
				
			||||||
            var user = new User { CommonName = "holger", IsActive = true, Id = -7, ParentId = germany.Id };
 | 
					            var user = new User { CommonName = Environment.UserName, IsActive = true, Id = -7, ParentId = users.Id };
 | 
				
			||||||
            modelBuilder.Entity<User>().HasData(user);
 | 
					            modelBuilder.Entity<User>().HasData(user);
 | 
				
			||||||
            var secGroup = new SecurityGroup { CommonName = "Global Admin", Id = -8, ParentId = groups.Id };
 | 
					            var secGroup = new SecurityGroup { CommonName = "Global Admin", Id = -8, ParentId = groups.Id };
 | 
				
			||||||
            modelBuilder.Entity<SecurityGroup>().HasData(secGroup);
 | 
					            modelBuilder.Entity<SecurityGroup>().HasData(secGroup);
 | 
				
			||||||
@@ -25,6 +28,7 @@ namespace UserService.DatabaseLayer.DataModels
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public static void CreateRelations(this ModelBuilder modelBuilder)
 | 
					        public static void CreateRelations(this ModelBuilder modelBuilder)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if (modelBuilder == null) throw new ArgumentNullException(nameof(modelBuilder));
 | 
				
			||||||
            modelBuilder.Entity<UserMember>()
 | 
					            modelBuilder.Entity<UserMember>()
 | 
				
			||||||
                .HasKey(bc => new { bc.MemberId, bc.UserId });
 | 
					                .HasKey(bc => new { bc.MemberId, bc.UserId });
 | 
				
			||||||
            modelBuilder.Entity<UserMember>()
 | 
					            modelBuilder.Entity<UserMember>()
 | 
				
			||||||
@@ -35,7 +39,6 @@ namespace UserService.DatabaseLayer.DataModels
 | 
				
			|||||||
                .HasOne(bc => bc.Member)
 | 
					                .HasOne(bc => bc.Member)
 | 
				
			||||||
                .WithMany(c => c!.Members)
 | 
					                .WithMany(c => c!.Members)
 | 
				
			||||||
                .HasForeignKey(bc => bc.MemberId);
 | 
					                .HasForeignKey(bc => bc.MemberId);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            modelBuilder.Entity<Node>()
 | 
					            modelBuilder.Entity<Node>()
 | 
				
			||||||
                .HasMany(c => c.Children)
 | 
					                .HasMany(c => c.Children)
 | 
				
			||||||
                .WithOne(e => e.Parent!)
 | 
					                .WithOne(e => e.Parent!)
 | 
				
			||||||
@@ -47,6 +50,7 @@ namespace UserService.DatabaseLayer.DataModels
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public static IEnumerable<SecurityGroup> GetSecurityGroups(this User user)
 | 
					        public static IEnumerable<SecurityGroup> GetSecurityGroups(this User user)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if (user == null) throw new ArgumentNullException(nameof(user));
 | 
				
			||||||
            foreach (var userMember in user.MemberOf)
 | 
					            foreach (var userMember in user.MemberOf)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (userMember.Member is SecurityGroup securityGroup)
 | 
					                if (userMember.Member is SecurityGroup securityGroup)
 | 
				
			||||||
@@ -62,6 +66,7 @@ namespace UserService.DatabaseLayer.DataModels
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public static IEnumerable<User> GetUsers(this SecurityGroup securityGroup)
 | 
					        public static IEnumerable<User> GetUsers(this SecurityGroup securityGroup)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if (securityGroup == null) throw new ArgumentNullException(nameof(securityGroup));
 | 
				
			||||||
            foreach (var userMember in securityGroup.Members)
 | 
					            foreach (var userMember in securityGroup.Members)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (userMember.User is null) continue;
 | 
					                if (userMember.User is null) continue;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,79 +0,0 @@
 | 
				
			|||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.ComponentModel.DataAnnotations;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace UserService.DatabaseLayer.DataModels
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public class OrganizationUnit : Node
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public Member? Manager { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <inheritdoc />
 | 
					 | 
				
			||||||
        public override string ToString()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					 | 
				
			||||||
            if (Level != 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                sb.Append("|");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            sb.Append('-', Level * 4);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return sb + CommonName;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class SecurityGroup : Member
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class User : Member
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public string? FirstName { get; set; }
 | 
					 | 
				
			||||||
        public string? LastName { get; set; }
 | 
					 | 
				
			||||||
        public bool IsActive { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public string FullName => $"{FirstName} {LastName}";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public IEnumerable<UserMember> MemberOf { get; set; } = new List<UserMember>();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class UserMember
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public int MemberId { get; set; }
 | 
					 | 
				
			||||||
        public Member? Member { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public int UserId { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public User? User { get; set; }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public abstract class Member : Node
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        [EmailAddress]
 | 
					 | 
				
			||||||
        public string? EMail { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public ICollection<UserMember> Members { get; set; } = new List<UserMember>();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public abstract class Node : ICloneable
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public int Id { get; set; }
 | 
					 | 
				
			||||||
        [Required] public string CommonName { get; set; } = null!;
 | 
					 | 
				
			||||||
        public string? Description { get; set; }
 | 
					 | 
				
			||||||
        public ICollection<Node> Children { get; set; } = new List<Node>();
 | 
					 | 
				
			||||||
        public Node? Parent { get; set; } //Parent
 | 
					 | 
				
			||||||
        public int? ParentId { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override string ToString() => $"[{GetType().Name}] {Id:D5} {CommonName}";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public int Level => Parent?.Level + 1 ?? 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <inheritdoc />
 | 
					 | 
				
			||||||
        public virtual object Clone() => MemberwiseClone();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using Microsoft.EntityFrameworkCore;
 | 
					using Microsoft.EntityFrameworkCore;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace UserService.DatabaseLayer.DataModels
 | 
					namespace UserService.DatabaseLayer.DataModels
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,16 +9,16 @@ using UserService.DatabaseLayer.DataModels;
 | 
				
			|||||||
namespace UserService.DatabaseLayer.Migrations
 | 
					namespace UserService.DatabaseLayer.Migrations
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    [DbContext(typeof(UserServiceDbContext))]
 | 
					    [DbContext(typeof(UserServiceDbContext))]
 | 
				
			||||||
    [Migration("20200725195658_initial")]
 | 
					    [Migration("20200821193933_InitialCreate")]
 | 
				
			||||||
    partial class initial
 | 
					    partial class InitialCreate
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        protected override void BuildTargetModel(ModelBuilder modelBuilder)
 | 
					        protected override void BuildTargetModel(ModelBuilder modelBuilder)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
#pragma warning disable 612, 618
 | 
					#pragma warning disable 612, 618
 | 
				
			||||||
            modelBuilder
 | 
					            modelBuilder
 | 
				
			||||||
                .HasAnnotation("ProductVersion", "3.1.6");
 | 
					                .HasAnnotation("ProductVersion", "3.1.7");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.Node", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.Node", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.Property<int>("Id")
 | 
					                    b.Property<int>("Id")
 | 
				
			||||||
                        .ValueGeneratedOnAdd()
 | 
					                        .ValueGeneratedOnAdd()
 | 
				
			||||||
@@ -47,7 +47,7 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                    b.HasDiscriminator<string>("Discriminator").HasValue("Node");
 | 
					                    b.HasDiscriminator<string>("Discriminator").HasValue("Node");
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.UserMember", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.UserMember", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.Property<int>("MemberId")
 | 
					                    b.Property<int>("MemberId")
 | 
				
			||||||
                        .HasColumnType("INTEGER");
 | 
					                        .HasColumnType("INTEGER");
 | 
				
			||||||
@@ -69,9 +69,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                        });
 | 
					                        });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.Member", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.Member", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasBaseType("UserService.DatabaseLayer.DataModels.Node");
 | 
					                    b.HasBaseType("UserService.Infrastructure.DataModels.Node");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.Property<string>("EMail")
 | 
					                    b.Property<string>("EMail")
 | 
				
			||||||
                        .HasColumnType("TEXT");
 | 
					                        .HasColumnType("TEXT");
 | 
				
			||||||
@@ -79,9 +79,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                    b.HasDiscriminator().HasValue("Member");
 | 
					                    b.HasDiscriminator().HasValue("Member");
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.OrganizationUnit", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.OrganizationUnit", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasBaseType("UserService.DatabaseLayer.DataModels.Node");
 | 
					                    b.HasBaseType("UserService.Infrastructure.DataModels.Node");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.Property<int?>("ManagerId")
 | 
					                    b.Property<int?>("ManagerId")
 | 
				
			||||||
                        .HasColumnType("INTEGER");
 | 
					                        .HasColumnType("INTEGER");
 | 
				
			||||||
@@ -127,9 +127,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                        });
 | 
					                        });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.SecurityGroup", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.SecurityGroup", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasBaseType("UserService.DatabaseLayer.DataModels.Member");
 | 
					                    b.HasBaseType("UserService.Infrastructure.DataModels.Member");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.HasDiscriminator().HasValue("SecurityGroup");
 | 
					                    b.HasDiscriminator().HasValue("SecurityGroup");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,9 +142,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                        });
 | 
					                        });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.User", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.User", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasBaseType("UserService.DatabaseLayer.DataModels.Member");
 | 
					                    b.HasBaseType("UserService.Infrastructure.DataModels.Member");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.Property<string>("FirstName")
 | 
					                    b.Property<string>("FirstName")
 | 
				
			||||||
                        .HasColumnType("TEXT");
 | 
					                        .HasColumnType("TEXT");
 | 
				
			||||||
@@ -162,36 +162,36 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            Id = -7,
 | 
					                            Id = -7,
 | 
				
			||||||
                            CommonName = "holger",
 | 
					                            CommonName = "holger",
 | 
				
			||||||
                            ParentId = -6,
 | 
					                            ParentId = -2,
 | 
				
			||||||
                            IsActive = true
 | 
					                            IsActive = true
 | 
				
			||||||
                        });
 | 
					                        });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.Node", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.Node", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasOne("UserService.DatabaseLayer.DataModels.Node", "Parent")
 | 
					                    b.HasOne("UserService.Infrastructure.DataModels.Node", "Parent")
 | 
				
			||||||
                        .WithMany("Children")
 | 
					                        .WithMany("Children")
 | 
				
			||||||
                        .HasForeignKey("ParentId");
 | 
					                        .HasForeignKey("ParentId");
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.UserMember", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.UserMember", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasOne("UserService.DatabaseLayer.DataModels.Member", "Member")
 | 
					                    b.HasOne("UserService.Infrastructure.DataModels.Member", "Member")
 | 
				
			||||||
                        .WithMany("Members")
 | 
					                        .WithMany("Members")
 | 
				
			||||||
                        .HasForeignKey("MemberId")
 | 
					                        .HasForeignKey("MemberId")
 | 
				
			||||||
                        .OnDelete(DeleteBehavior.Cascade)
 | 
					                        .OnDelete(DeleteBehavior.Cascade)
 | 
				
			||||||
                        .IsRequired();
 | 
					                        .IsRequired();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.HasOne("UserService.DatabaseLayer.DataModels.User", "User")
 | 
					                    b.HasOne("UserService.Infrastructure.DataModels.User", "User")
 | 
				
			||||||
                        .WithMany("MemberOf")
 | 
					                        .WithMany("MemberOf")
 | 
				
			||||||
                        .HasForeignKey("UserId")
 | 
					                        .HasForeignKey("UserId")
 | 
				
			||||||
                        .OnDelete(DeleteBehavior.Cascade)
 | 
					                        .OnDelete(DeleteBehavior.Cascade)
 | 
				
			||||||
                        .IsRequired();
 | 
					                        .IsRequired();
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.OrganizationUnit", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.OrganizationUnit", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasOne("UserService.DatabaseLayer.DataModels.Member", "Manager")
 | 
					                    b.HasOne("UserService.Infrastructure.DataModels.Member", "Manager")
 | 
				
			||||||
                        .WithMany()
 | 
					                        .WithMany()
 | 
				
			||||||
                        .HasForeignKey("ManagerId");
 | 
					                        .HasForeignKey("ManagerId");
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace UserService.DatabaseLayer.Migrations
 | 
					namespace UserService.DatabaseLayer.Migrations
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public partial class initial : Migration
 | 
					    public partial class InitialCreate : Migration
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        protected override void Up(MigrationBuilder migrationBuilder)
 | 
					        protected override void Up(MigrationBuilder migrationBuilder)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -90,13 +90,13 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            migrationBuilder.InsertData(
 | 
					            migrationBuilder.InsertData(
 | 
				
			||||||
                table: "Node",
 | 
					                table: "Node",
 | 
				
			||||||
                columns: new[] { "Id", "CommonName", "Description", "Discriminator", "ParentId", "EMail" },
 | 
					                columns: new[] { "Id", "CommonName", "Description", "Discriminator", "ParentId", "EMail", "FirstName", "IsActive", "LastName" },
 | 
				
			||||||
                values: new object[] { -8, "Global Admin", null, "SecurityGroup", -1, null });
 | 
					                values: new object[] { -7, "holger", null, "User", -2, null, null, true, null });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            migrationBuilder.InsertData(
 | 
					            migrationBuilder.InsertData(
 | 
				
			||||||
                table: "Node",
 | 
					                table: "Node",
 | 
				
			||||||
                columns: new[] { "Id", "CommonName", "Description", "Discriminator", "ParentId", "EMail", "FirstName", "IsActive", "LastName" },
 | 
					                columns: new[] { "Id", "CommonName", "Description", "Discriminator", "ParentId", "EMail" },
 | 
				
			||||||
                values: new object[] { -7, "holger", null, "User", -6, null, null, true, null });
 | 
					                values: new object[] { -8, "Global Admin", null, "SecurityGroup", -1, null });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            migrationBuilder.InsertData(
 | 
					            migrationBuilder.InsertData(
 | 
				
			||||||
                table: "Node",
 | 
					                table: "Node",
 | 
				
			||||||
@@ -14,9 +14,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
#pragma warning disable 612, 618
 | 
					#pragma warning disable 612, 618
 | 
				
			||||||
            modelBuilder
 | 
					            modelBuilder
 | 
				
			||||||
                .HasAnnotation("ProductVersion", "3.1.6");
 | 
					                .HasAnnotation("ProductVersion", "3.1.7");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.Node", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.Node", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.Property<int>("Id")
 | 
					                    b.Property<int>("Id")
 | 
				
			||||||
                        .ValueGeneratedOnAdd()
 | 
					                        .ValueGeneratedOnAdd()
 | 
				
			||||||
@@ -45,7 +45,7 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                    b.HasDiscriminator<string>("Discriminator").HasValue("Node");
 | 
					                    b.HasDiscriminator<string>("Discriminator").HasValue("Node");
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.UserMember", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.UserMember", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.Property<int>("MemberId")
 | 
					                    b.Property<int>("MemberId")
 | 
				
			||||||
                        .HasColumnType("INTEGER");
 | 
					                        .HasColumnType("INTEGER");
 | 
				
			||||||
@@ -67,9 +67,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                        });
 | 
					                        });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.Member", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.Member", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasBaseType("UserService.DatabaseLayer.DataModels.Node");
 | 
					                    b.HasBaseType("UserService.Infrastructure.DataModels.Node");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.Property<string>("EMail")
 | 
					                    b.Property<string>("EMail")
 | 
				
			||||||
                        .HasColumnType("TEXT");
 | 
					                        .HasColumnType("TEXT");
 | 
				
			||||||
@@ -77,9 +77,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                    b.HasDiscriminator().HasValue("Member");
 | 
					                    b.HasDiscriminator().HasValue("Member");
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.OrganizationUnit", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.OrganizationUnit", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasBaseType("UserService.DatabaseLayer.DataModels.Node");
 | 
					                    b.HasBaseType("UserService.Infrastructure.DataModels.Node");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.Property<int?>("ManagerId")
 | 
					                    b.Property<int?>("ManagerId")
 | 
				
			||||||
                        .HasColumnType("INTEGER");
 | 
					                        .HasColumnType("INTEGER");
 | 
				
			||||||
@@ -125,9 +125,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                        });
 | 
					                        });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.SecurityGroup", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.SecurityGroup", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasBaseType("UserService.DatabaseLayer.DataModels.Member");
 | 
					                    b.HasBaseType("UserService.Infrastructure.DataModels.Member");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.HasDiscriminator().HasValue("SecurityGroup");
 | 
					                    b.HasDiscriminator().HasValue("SecurityGroup");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -140,9 +140,9 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                        });
 | 
					                        });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.User", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.User", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasBaseType("UserService.DatabaseLayer.DataModels.Member");
 | 
					                    b.HasBaseType("UserService.Infrastructure.DataModels.Member");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.Property<string>("FirstName")
 | 
					                    b.Property<string>("FirstName")
 | 
				
			||||||
                        .HasColumnType("TEXT");
 | 
					                        .HasColumnType("TEXT");
 | 
				
			||||||
@@ -160,36 +160,36 @@ namespace UserService.DatabaseLayer.Migrations
 | 
				
			|||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            Id = -7,
 | 
					                            Id = -7,
 | 
				
			||||||
                            CommonName = "holger",
 | 
					                            CommonName = "holger",
 | 
				
			||||||
                            ParentId = -6,
 | 
					                            ParentId = -2,
 | 
				
			||||||
                            IsActive = true
 | 
					                            IsActive = true
 | 
				
			||||||
                        });
 | 
					                        });
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.Node", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.Node", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasOne("UserService.DatabaseLayer.DataModels.Node", "Parent")
 | 
					                    b.HasOne("UserService.Infrastructure.DataModels.Node", "Parent")
 | 
				
			||||||
                        .WithMany("Children")
 | 
					                        .WithMany("Children")
 | 
				
			||||||
                        .HasForeignKey("ParentId");
 | 
					                        .HasForeignKey("ParentId");
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.UserMember", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.UserMember", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasOne("UserService.DatabaseLayer.DataModels.Member", "Member")
 | 
					                    b.HasOne("UserService.Infrastructure.DataModels.Member", "Member")
 | 
				
			||||||
                        .WithMany("Members")
 | 
					                        .WithMany("Members")
 | 
				
			||||||
                        .HasForeignKey("MemberId")
 | 
					                        .HasForeignKey("MemberId")
 | 
				
			||||||
                        .OnDelete(DeleteBehavior.Cascade)
 | 
					                        .OnDelete(DeleteBehavior.Cascade)
 | 
				
			||||||
                        .IsRequired();
 | 
					                        .IsRequired();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    b.HasOne("UserService.DatabaseLayer.DataModels.User", "User")
 | 
					                    b.HasOne("UserService.Infrastructure.DataModels.User", "User")
 | 
				
			||||||
                        .WithMany("MemberOf")
 | 
					                        .WithMany("MemberOf")
 | 
				
			||||||
                        .HasForeignKey("UserId")
 | 
					                        .HasForeignKey("UserId")
 | 
				
			||||||
                        .OnDelete(DeleteBehavior.Cascade)
 | 
					                        .OnDelete(DeleteBehavior.Cascade)
 | 
				
			||||||
                        .IsRequired();
 | 
					                        .IsRequired();
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            modelBuilder.Entity("UserService.DatabaseLayer.DataModels.OrganizationUnit", b =>
 | 
					            modelBuilder.Entity("UserService.Infrastructure.DataModels.OrganizationUnit", b =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    b.HasOne("UserService.DatabaseLayer.DataModels.Member", "Manager")
 | 
					                    b.HasOne("UserService.Infrastructure.DataModels.Member", "Manager")
 | 
				
			||||||
                        .WithMany()
 | 
					                        .WithMany()
 | 
				
			||||||
                        .HasForeignKey("ManagerId");
 | 
					                        .HasForeignKey("ManagerId");
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								UserService.DatabaseLayer/Queryable.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								UserService.DatabaseLayer/Queryable.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReSharper disable once CheckNamespace
 | 
				
			||||||
 | 
					namespace System.Linq
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static class Queryable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Makes a where filtering, if it is not null.
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public static IQueryable<TSource> WhereOrDefault<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>>? predicate)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (source == null) throw new ArgumentNullException(nameof(source));
 | 
				
			||||||
 | 
					            return predicate is null ? source : source.Where(predicate);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,55 +1,57 @@
 | 
				
			|||||||
using System;
 | 
					#nullable enable
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Runtime.CompilerServices;
 | 
					 | 
				
			||||||
using System.Security.Cryptography.X509Certificates;
 | 
					 | 
				
			||||||
using System.Threading;
 | 
					using System.Threading;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using Microsoft.EntityFrameworkCore;
 | 
					using Microsoft.EntityFrameworkCore;
 | 
				
			||||||
using UserService.DatabaseLayer.DataModels;
 | 
					using UserService.DatabaseLayer.DataModels;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace UserService.DatabaseLayer.Repository
 | 
					namespace UserService.DatabaseLayer.Repository
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class BaseRepository<T> where T : Node
 | 
					    public class BaseRepository<T> where T : Node
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        protected readonly Func<UserServiceDbContext, DbSet<T>> _context;
 | 
					        protected Func<UserServiceDbContext, DbSet<T>> Context { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected BaseRepository(Func<UserServiceDbContext, DbSet<T>> context)
 | 
					        protected BaseRepository(Func<UserServiceDbContext, DbSet<T>> context)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _context = context;
 | 
					            Context = context;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public virtual async Task<IReadOnlyList<T>> GetAllAsync(CancellationToken token = default)
 | 
					        public virtual async Task<IReadOnlyList<T>> GetAllAsync(Expression<Func<T, bool>>? predicate = null, CancellationToken token = default)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					            await using var db = new UserServiceDbContext();
 | 
				
			||||||
            return await _context(db).Include(x => x.Parent).ToListAsync(token);
 | 
					            return await Context(db).Include(x => x.Parent).WhereOrDefault(predicate).ToListAsync(token).ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task<T?> GetAsync(Expression<Func<T, bool>> predicate, CancellationToken token = default)
 | 
					        public async Task<T?> GetAsync(Expression<Func<T, bool>> predicate, CancellationToken token = default)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					            await using var db = new UserServiceDbContext();
 | 
				
			||||||
            return await _context(db).FirstOrDefaultAsync(predicate, token);
 | 
					            return await Context(db).FirstOrDefaultAsync(predicate, token).ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task AddAsync(T entity, CancellationToken token = default)
 | 
					        public async Task AddAsync(T entity, CancellationToken token = default)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					            await using var db = new UserServiceDbContext();
 | 
				
			||||||
            await _context(db).AddAsync(@entity, token);
 | 
					            await Context(db).AddAsync(@entity, token).ConfigureAwait(false);
 | 
				
			||||||
            await db.SaveChangesAsync(token);
 | 
					            await db.SaveChangesAsync(token).ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task UpdateAsync(T entity, CancellationToken token = default)
 | 
					        public async Task<bool> UpdateAsync(T entity, CancellationToken token = default)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					            await using var db = new UserServiceDbContext();
 | 
				
			||||||
            _context(db).Update(entity);
 | 
					            Context(db).Update(entity);
 | 
				
			||||||
            await db.SaveChangesAsync(token);
 | 
					            var items= await db.SaveChangesAsync(token).ConfigureAwait(false);
 | 
				
			||||||
 | 
					            return items > 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task DeleteAsync(T entity, CancellationToken token = default)
 | 
					        public async Task DeleteAsync(T entity, CancellationToken token = default)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					            await using var db = new UserServiceDbContext();
 | 
				
			||||||
            _context(db).Remove(entity);
 | 
					            Context(db).Remove(entity);
 | 
				
			||||||
            await db.SaveChangesAsync(token);
 | 
					            await db.SaveChangesAsync(token).ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,18 +1,19 @@
 | 
				
			|||||||
using System;
 | 
					#nullable enable
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
using System.Threading;
 | 
					using System.Threading;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using UserService.DatabaseLayer.DataModels;
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace UserService.DatabaseLayer.Repository
 | 
					namespace UserService.DatabaseLayer.Repository
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public interface IRepository<T> where T : Node
 | 
					    public interface IRepository<T> where T : Node
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Task<IReadOnlyList<T>> GetAllAsync(CancellationToken token = default);
 | 
					        Task<IReadOnlyList<T>> GetAllAsync(Expression<Func<T, bool>>? predicate = null, CancellationToken token = default);
 | 
				
			||||||
        Task<T?> GetAsync(Expression<Func<T, bool>> predicate, CancellationToken token = default);
 | 
					        Task<T?> GetAsync(Expression<Func<T, bool>> predicate, CancellationToken token = default);
 | 
				
			||||||
        Task AddAsync(T entity, CancellationToken token = default);
 | 
					        Task AddAsync(T entity, CancellationToken token = default);
 | 
				
			||||||
        Task UpdateAsync(T entity, CancellationToken token = default);
 | 
					        Task<bool> UpdateAsync(T entity, CancellationToken token = default);
 | 
				
			||||||
        Task DeleteAsync(T entity, CancellationToken token = default);
 | 
					        Task DeleteAsync(T entity, CancellationToken token = default);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Microsoft.EntityFrameworkCore;
 | 
				
			||||||
 | 
					using UserService.DatabaseLayer.DataModels;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.DatabaseLayer.Repository
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OrganizationUnitsRepository : BaseRepository<OrganizationUnit>, IOrganizationUnitsRepository
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public OrganizationUnitsRepository() : base(x => x.OrganizationUnits)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <inheritdoc cref="GetAllAsync" />
 | 
				
			||||||
 | 
					        public override async Task<IReadOnlyList<OrganizationUnit>> GetAllAsync(
 | 
				
			||||||
 | 
					            Expression<Func<OrganizationUnit, bool>>? predicate = null, CancellationToken token = default)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await using var db = new UserServiceDbContext();
 | 
				
			||||||
 | 
					            var result = new List<OrganizationUnit>();
 | 
				
			||||||
 | 
					            var rootOus = await Context(db)
 | 
				
			||||||
 | 
					                .Include(x => x.Parent)
 | 
				
			||||||
 | 
					                .WhereOrDefault(predicate)
 | 
				
			||||||
 | 
					                .ToListAsync(cancellationToken: token).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            IEnumerable<OrganizationUnit> Rec(Node node)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (!(node is OrganizationUnit organizationUnit)) yield break;
 | 
				
			||||||
 | 
					                yield return organizationUnit;
 | 
				
			||||||
 | 
					                foreach (var ouChild in rootOus.Where(x => x.ParentId != null && x.ParentId == organizationUnit.Id))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var unit in Rec(ouChild))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        yield return unit;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var ou in rootOus.Where(x => x.ParentId is null))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                result.AddRange(Rec(ou));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,121 +0,0 @@
 | 
				
			|||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Linq.Expressions;
 | 
					 | 
				
			||||||
using System.Runtime.CompilerServices;
 | 
					 | 
				
			||||||
using System.Threading;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Microsoft.EntityFrameworkCore;
 | 
					 | 
				
			||||||
using UserService.DatabaseLayer.DataModels;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace UserService.DatabaseLayer.Repository
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public class OrganizationUnitsRepository : BaseRepository<OrganizationUnit>, IOrganizationUnitsRepository
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public OrganizationUnitsRepository() : base(x => x.OrganizationUnits)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <inheritdoc />
 | 
					 | 
				
			||||||
        public override async Task<IReadOnlyList<OrganizationUnit>> GetAllAsync(CancellationToken token = default)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					 | 
				
			||||||
            var result = new List<OrganizationUnit>();
 | 
					 | 
				
			||||||
            var rootOus = await _context(db)
 | 
					 | 
				
			||||||
                .Include(x => x.Parent)
 | 
					 | 
				
			||||||
                .ToListAsync(token);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            IEnumerable<OrganizationUnit> Rec(Node node)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (!(node is OrganizationUnit organizationUnit)) yield break;
 | 
					 | 
				
			||||||
                yield return organizationUnit;
 | 
					 | 
				
			||||||
                foreach (var ouChild in rootOus.Where(x=>x.ParentId != null && x.ParentId == organizationUnit.Id))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    foreach (var unit in Rec(ouChild))
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        yield return unit;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            foreach (var ou in rootOus.Where(x=> x.ParentId is null))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                result.AddRange(Rec(ou));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return result;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class SecurityGroupsRepository : BaseRepository<SecurityGroup>, ISecurityGroupsRepository
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public SecurityGroupsRepository() : base(x=> x.SecurityGroups)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class UsersRepository : BaseRepository<User>, IUsersRepository
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public UsersRepository() : base(x => x.Users)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class NodesRepository : INodesRepository
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public NodesRepository()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public static async IAsyncEnumerable<Node> GetNodesAsync([EnumeratorCancellation] CancellationToken token = default)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					 | 
				
			||||||
            await foreach (var note in db.OrganizationUnits.AsAsyncEnumerable().WithCancellation(token))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                yield return note;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            await foreach (var node in db.SecurityGroups.AsAsyncEnumerable().WithCancellation(token))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                yield return node;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            await foreach (var node in db.Users.AsAsyncEnumerable().WithCancellation(token))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                yield return node;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public async Task<IReadOnlyList<Node>> GetAllAsync(CancellationToken token = default)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            var list = new List<Node>();
 | 
					 | 
				
			||||||
            await foreach (var node in GetNodesAsync(token))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                list.Add(node);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return list;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public Task<Node?> GetAsync(Expression<Func<Node, bool>> predicate, CancellationToken token = default)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            throw new NotImplementedException();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public Task AddAsync(Node entity, CancellationToken token = default)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            throw new NotImplementedException();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public Task UpdateAsync(Node entity, CancellationToken token = default)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            throw new NotImplementedException();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public Task DeleteAsync(Node entity, CancellationToken token = default)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            throw new NotImplementedException();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.DatabaseLayer.Repository
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class SecurityGroupsRepository : BaseRepository<SecurityGroup>, ISecurityGroupsRepository
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public SecurityGroupsRepository() : base(x => x.SecurityGroups)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								UserService.DatabaseLayer/Repository/UsersRepository.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								UserService.DatabaseLayer/Repository/UsersRepository.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.DatabaseLayer.Repository
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class UsersRepository : BaseRepository<User>, IUsersRepository
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public UsersRepository() : base(x => x.Users)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,16 +2,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <PropertyGroup>
 | 
					    <PropertyGroup>
 | 
				
			||||||
        <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
					        <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
				
			||||||
        <LangVersion>8</LangVersion>
 | 
					        <LangVersion>latest</LangVersion>
 | 
				
			||||||
        <Nullable>enable</Nullable>
 | 
					        <Nullable>enable</Nullable>
 | 
				
			||||||
    </PropertyGroup>
 | 
					    </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <ItemGroup>
 | 
					    <ItemGroup>
 | 
				
			||||||
      <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.6">
 | 
					      <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
 | 
				
			||||||
        <PrivateAssets>all</PrivateAssets>
 | 
					        <PrivateAssets>all</PrivateAssets>
 | 
				
			||||||
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
					        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
				
			||||||
      </PackageReference>
 | 
					      </PackageReference>
 | 
				
			||||||
      <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.6" />
 | 
					      <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.7">
 | 
				
			||||||
 | 
					        <PrivateAssets>all</PrivateAssets>
 | 
				
			||||||
 | 
					        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
				
			||||||
 | 
					      </PackageReference>
 | 
				
			||||||
 | 
					      <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.7" />
 | 
				
			||||||
 | 
					    </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ItemGroup>
 | 
				
			||||||
 | 
					      <ProjectReference Include="..\UserService.Infrastructure\UserService.Infrastructure.csproj" />
 | 
				
			||||||
    </ItemGroup>
 | 
					    </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								UserService.Infrastructure/DataModels/Member.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								UserService.Infrastructure/DataModels/Member.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel.DataAnnotations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.Infrastructure.DataModels
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public abstract class Member : Node
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public ICollection<UserMember> Members { get; set; } = new List<UserMember>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								UserService.Infrastructure/DataModels/Node.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								UserService.Infrastructure/DataModels/Node.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					#nullable enable
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel.DataAnnotations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.Infrastructure.DataModels
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public abstract class Node : ICloneable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public int Id { get; set; }
 | 
				
			||||||
 | 
					        [Required] public string CommonName { get; set; } = null!;
 | 
				
			||||||
 | 
					        public string? Description { get; set; }
 | 
				
			||||||
 | 
					        public ICollection<Node> Children { get; set; } = new List<Node>();
 | 
				
			||||||
 | 
					        public Node? Parent { get; set; } //Parent
 | 
				
			||||||
 | 
					        public int? ParentId { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override string ToString() => CommonName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public int Level => Parent?.Level + 1 ?? 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <inheritdoc />
 | 
				
			||||||
 | 
					        public virtual object Clone() => MemberwiseClone();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					namespace UserService.Infrastructure.DataModels
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class OrganizationUnit : Node
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public Member? Manager { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								UserService.Infrastructure/DataModels/SecurityGroup.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								UserService.Infrastructure/DataModels/SecurityGroup.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					namespace UserService.Infrastructure.DataModels
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class SecurityGroup : Member
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								UserService.Infrastructure/DataModels/User.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								UserService.Infrastructure/DataModels/User.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel.DataAnnotations;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.Infrastructure.DataModels
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class User : Member
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public string? FirstName { get; set; }
 | 
				
			||||||
 | 
					        public string? LastName { get; set; }
 | 
				
			||||||
 | 
					        public bool IsActive { get; set; }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        [EmailAddress]
 | 
				
			||||||
 | 
					        public string? EMail { get; set; }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public string FullName => $"{FirstName} {LastName}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<UserMember> MemberOf { get; set; } = new List<UserMember>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								UserService.Infrastructure/DataModels/UserMember.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								UserService.Infrastructure/DataModels/UserMember.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					namespace UserService.Infrastructure.DataModels
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class UserMember
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public int MemberId { get; set; }
 | 
				
			||||||
 | 
					        public Member? Member { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public int UserId { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public User? User { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								UserService.Infrastructure/NodeExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								UserService.Infrastructure/NodeExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.Infrastructure
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static class NodeExtensions
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static void MapFields(this User user, Dictionary<string, object> values)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (user == null) throw new ArgumentNullException(nameof(user));
 | 
				
			||||||
 | 
					            if (values == null) throw new ArgumentNullException(nameof(values));
 | 
				
			||||||
 | 
					            var properties = user.GetType().GetProperties();
 | 
				
			||||||
 | 
					            foreach (var keyValuePair in values)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var propertyInfo = properties.FirstOrDefault(x => x.Name == keyValuePair.Key);
 | 
				
			||||||
 | 
					                if (propertyInfo == null) continue;
 | 
				
			||||||
 | 
					                propertyInfo.SetValue(user, keyValuePair.Value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								UserService.Infrastructure/UserService.Infrastructure.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								UserService.Infrastructure/UserService.Infrastructure.csproj
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <TargetFramework>netstandard2.0</TargetFramework>
 | 
				
			||||||
 | 
					    <LangVersion>latest</LangVersion>
 | 
				
			||||||
 | 
					    <Nullable>enable</Nullable>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <PackageReference Include="System.ComponentModel.Annotations" Version="4.3.0" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										22
									
								
								UserService.Infrastructure/Validators.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								UserService.Infrastructure/Validators.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel.DataAnnotations;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.Infrastructure
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static class Validators
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static bool? ValidateEmail(string? mailAddress)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(mailAddress)) return null;
 | 
				
			||||||
 | 
					            return new EmailAddressAttribute().IsValid(mailAddress);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static bool? ValidateCommonName(string? commonName, IEnumerable<Member> users)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(commonName)) return false;
 | 
				
			||||||
 | 
					            return users.All(x => x.CommonName != commonName);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,12 +1,11 @@
 | 
				
			|||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Security.Cryptography.X509Certificates;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Microsoft.EntityFrameworkCore;
 | 
					using Microsoft.EntityFrameworkCore;
 | 
				
			||||||
using NUnit.Framework;
 | 
					using NUnit.Framework;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using UserService.DatabaseLayer.DataModels;
 | 
					using UserService.DatabaseLayer.DataModels;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace UserService.Test
 | 
					namespace UserService.Test
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -21,10 +20,10 @@ namespace UserService.Test
 | 
				
			|||||||
        public async Task Test1()
 | 
					        public async Task Test1()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					            await using var db = new UserServiceDbContext();
 | 
				
			||||||
            var user = await db.Users.FirstOrDefaultAsync();
 | 
					            var user = await db.Users.FirstOrDefaultAsync().ConfigureAwait(false);
 | 
				
			||||||
            var secGroup = await db.SecurityGroups.FirstOrDefaultAsync();
 | 
					            var secGroup = await db.SecurityGroups.FirstOrDefaultAsync().ConfigureAwait(false);
 | 
				
			||||||
            var ous = await db.OrganizationUnits.ToListAsync();
 | 
					            var ous = await db.OrganizationUnits.ToListAsync().ConfigureAwait(false);
 | 
				
			||||||
            var mo = await db.UserMembers.ToListAsync();
 | 
					            var mo = await db.UserMembers.ToListAsync().ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var securityGroupsOfUser = user.GetSecurityGroups();
 | 
					            var securityGroupsOfUser = user.GetSecurityGroups();
 | 
				
			||||||
            var usersOfSecurityGroup = secGroup.GetUsers();
 | 
					            var usersOfSecurityGroup = secGroup.GetUsers();
 | 
				
			||||||
@@ -40,12 +39,11 @@ namespace UserService.Test
 | 
				
			|||||||
        public async Task Test2()
 | 
					        public async Task Test2()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await using var db = new UserServiceDbContext();
 | 
					            await using var db = new UserServiceDbContext();
 | 
				
			||||||
            var ous = await db.OrganizationUnits.ToListAsync();
 | 
					            var ous = await db.OrganizationUnits.ToListAsync().ConfigureAwait(false);
 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
            NewMethod(ous, null, 0, ref sb);
 | 
					            NewMethod(ous, null, 0, ref sb);
 | 
				
			||||||
            var result = sb.ToString();
 | 
					            var result = sb.ToString();
 | 
				
			||||||
            Assert.Pass();
 | 
					            Assert.Pass();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void NewMethod(IEnumerable<OrganizationUnit> ous, Node parent, int level, ref StringBuilder sb)
 | 
					        private static void NewMethod(IEnumerable<OrganizationUnit> ous, Node parent, int level, ref StringBuilder sb)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,21 @@
 | 
				
			|||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
					    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <IsPackable>false</IsPackable>
 | 
					    <IsPackable>false</IsPackable>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <LangVersion>latest</LangVersion>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
 | 
				
			||||||
 | 
					      <PrivateAssets>all</PrivateAssets>
 | 
				
			||||||
 | 
					      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
				
			||||||
 | 
					    </PackageReference>
 | 
				
			||||||
    <PackageReference Include="nunit" Version="3.12.0" />
 | 
					    <PackageReference Include="nunit" Version="3.12.0" />
 | 
				
			||||||
    <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
 | 
					    <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
 | 
					    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								UserService.db
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								UserService.db
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -9,6 +9,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UserService.Test", "UserSer
 | 
				
			|||||||
EndProject
 | 
					EndProject
 | 
				
			||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UserService.DatabaseLayer", "UserService.DatabaseLayer\UserService.DatabaseLayer.csproj", "{4505C991-7E39-416F-94E5-D906DD0D90F9}"
 | 
					Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UserService.DatabaseLayer", "UserService.DatabaseLayer\UserService.DatabaseLayer.csproj", "{4505C991-7E39-416F-94E5-D906DD0D90F9}"
 | 
				
			||||||
EndProject
 | 
					EndProject
 | 
				
			||||||
 | 
					Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A8D411B0-CD71-4448-9D4F-12898D0CCDD6}"
 | 
				
			||||||
 | 
						ProjectSection(SolutionItems) = preProject
 | 
				
			||||||
 | 
							.editorconfig = .editorconfig
 | 
				
			||||||
 | 
						EndProjectSection
 | 
				
			||||||
 | 
					EndProject
 | 
				
			||||||
 | 
					Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserService.Infrastructure", "UserService.Infrastructure\UserService.Infrastructure.csproj", "{586BD023-5C7B-4D9C-A17E-A0D5CEDADD20}"
 | 
				
			||||||
 | 
					EndProject
 | 
				
			||||||
Global
 | 
					Global
 | 
				
			||||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
						GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
				
			||||||
		Debug|Any CPU = Debug|Any CPU
 | 
							Debug|Any CPU = Debug|Any CPU
 | 
				
			||||||
@@ -27,6 +34,10 @@ Global
 | 
				
			|||||||
		{4505C991-7E39-416F-94E5-D906DD0D90F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
							{4505C991-7E39-416F-94E5-D906DD0D90F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
				
			||||||
		{4505C991-7E39-416F-94E5-D906DD0D90F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
							{4505C991-7E39-416F-94E5-D906DD0D90F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
		{4505C991-7E39-416F-94E5-D906DD0D90F9}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
							{4505C991-7E39-416F-94E5-D906DD0D90F9}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{586BD023-5C7B-4D9C-A17E-A0D5CEDADD20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{586BD023-5C7B-4D9C-A17E-A0D5CEDADD20}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{586BD023-5C7B-4D9C-A17E-A0D5CEDADD20}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{586BD023-5C7B-4D9C-A17E-A0D5CEDADD20}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
	EndGlobalSection
 | 
						EndGlobalSection
 | 
				
			||||||
	GlobalSection(SolutionProperties) = preSolution
 | 
						GlobalSection(SolutionProperties) = preSolution
 | 
				
			||||||
		HideSolutionNode = FALSE
 | 
							HideSolutionNode = FALSE
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
 | 
					<CascadingAuthenticationState>
 | 
				
			||||||
<CascadingAuthenticationState>
 | 
					 | 
				
			||||||
    <Router AppAssembly="@typeof(Program).Assembly">
 | 
					    <Router AppAssembly="@typeof(Program).Assembly">
 | 
				
			||||||
        <Found Context="routeData">
 | 
					        <Found Context="routeData">
 | 
				
			||||||
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
 | 
					            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,12 @@
 | 
				
			|||||||
@page "/directory"
 | 
					@page "/directory"
 | 
				
			||||||
@using UserService.DatabaseLayer.DataModels
 | 
					@inherits DirectoryBase
 | 
				
			||||||
@using UserService.DatabaseLayer.Repository
 | 
					 | 
				
			||||||
@inject IOrganizationUnitsRepository OuRepository
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
<h1>TODO</h1>
 | 
					<Row>
 | 
				
			||||||
 | 
					    <Column ColumnSize="ColumnSize.Is12">
 | 
				
			||||||
@if (_organizationUnits == null)
 | 
					        <h1>TODO</h1>
 | 
				
			||||||
 | 
					    </Column>
 | 
				
			||||||
 | 
					</Row>
 | 
				
			||||||
 | 
					@if (OrganizationUnits == null)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    <p>
 | 
					    <p>
 | 
				
			||||||
        <em>Loading...</em>
 | 
					        <em>Loading...</em>
 | 
				
			||||||
@@ -13,17 +14,20 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    <Row>
 | 
				
			||||||
 | 
					        <Column ColumnSize="ColumnSize.Is4">
 | 
				
			||||||
}
 | 
					            <TreeView Nodes="OrganizationUnits"
 | 
				
			||||||
@code {
 | 
					                      GetChildNodes="@(item => item?.Children)"
 | 
				
			||||||
    private IReadOnlyList<OrganizationUnit> _organizationUnits;
 | 
					                      HasChildNodes="@(item => item?.Children?.Any() == true)"
 | 
				
			||||||
    private OrganizationUnit _selectedOu;
 | 
					                      @bind-SelectedNode="@SelectedNode">
 | 
				
			||||||
 | 
					                <NodeContent>
 | 
				
			||||||
    protected override async Task OnInitializedAsync()
 | 
					                    <Icon Name="IconName.Folder" />
 | 
				
			||||||
    {
 | 
					                    @context?.CommonName
 | 
				
			||||||
        _organizationUnits = (await OuRepository.GetAllAsync().ConfigureAwait(false)).Where(x=> x.Parent is null).ToList();
 | 
					                </NodeContent>
 | 
				
			||||||
    }
 | 
					            </TreeView>
 | 
				
			||||||
 | 
					        </Column>
 | 
				
			||||||
 | 
					        <Column ColumnSize="ColumnSize.Is4">
 | 
				
			||||||
 | 
					        </Column>
 | 
				
			||||||
 | 
					    </Row>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								UserService/Pages/Directory.razor.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								UserService/Pages/Directory.razor.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
 | 
					using UserService.DatabaseLayer.Repository;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.Pages
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DirectoryBase : ComponentBase
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private Node? _selectedNode;
 | 
				
			||||||
 | 
					        public IReadOnlyList<Node>? OrganizationUnits { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Node? SelectedNode
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            get => _selectedNode;
 | 
				
			||||||
 | 
					            set
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if(Equals(_selectedNode, value)) return;
 | 
				
			||||||
 | 
					                _selectedNode = value;
 | 
				
			||||||
 | 
					                OnSelectedNodeChanged(value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async void OnSelectedNodeChanged(Node? value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (value == null) return;
 | 
				
			||||||
 | 
					            Members = await UsersRepository.GetAllAsync(x => x.ParentId == value.Id).ConfigureAwait(false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IReadOnlyList<Member>? Members { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Inject] public IOrganizationUnitsRepository OuRepository { get; set; } = null!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Inject] public IUsersRepository UsersRepository { get; set; } = null!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override async Task OnInitializedAsync()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            OrganizationUnits = (await OuRepository.GetAllAsync().ConfigureAwait(false))
 | 
				
			||||||
 | 
					                .Where(x => x.Parent is null)
 | 
				
			||||||
 | 
					                .ToList();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								UserService/Pages/MembersBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								UserService/Pages/MembersBase.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Blazorise;
 | 
				
			||||||
 | 
					using Blazorise.DataGrid;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
 | 
					using UserService.Infrastructure;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace UserService.Pages
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public abstract class MembersBase<T> : ComponentBase where T : Member
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        protected IReadOnlyList<OrganizationUnit>? OrganizationUnits { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected IReadOnlyList<T>? Members { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected string? CustomFilterValue { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected abstract Task RowInsertingCallback(CancellableRowChange<T, Dictionary<string, object>> arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected abstract Task RowInsertedCallback(SavedRowItem<T, Dictionary<string, object>> arg);
 | 
				
			||||||
 | 
					        protected abstract Task RowDeletingCallback(CancellableRowChange<T> arg);
 | 
				
			||||||
 | 
					        protected abstract Task RowUpdatingCallback(CancellableRowChange<T, Dictionary<string, object>> arg);
 | 
				
			||||||
 | 
					        protected abstract bool OnCustomFilter(T model);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected void ValidateCommonName(ValidatorEventArgs e)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (e == null) throw new ArgumentNullException(nameof(e));
 | 
				
			||||||
 | 
					            var commonName = e.Value?.ToString();
 | 
				
			||||||
 | 
					            var validationResult = Validators.ValidateCommonName(commonName, Members ?? Enumerable.Empty<Member>());
 | 
				
			||||||
 | 
					            e.Status = validationResult == false ? ValidationStatus.Error : ValidationStatus.Success;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,62 +0,0 @@
 | 
				
			|||||||
@page "/organizationUnits"
 | 
					 | 
				
			||||||
@using UserService.DatabaseLayer.DataModels
 | 
					 | 
				
			||||||
@inherits OrganizationUnitsBase
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<h1>List of all organization units</h1>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@if (OrganizationUnits is null)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    <p>
 | 
					 | 
				
			||||||
        <em>Loading...</em>
 | 
					 | 
				
			||||||
    </p>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    <MatTable Items="@OrganizationUnits" class="mat-elevation-z5">
 | 
					 | 
				
			||||||
        <MatTableHeader>
 | 
					 | 
				
			||||||
            <th style="width: 20%">Common Name</th>
 | 
					 | 
				
			||||||
            <th style="width: 20%">Description</th>
 | 
					 | 
				
			||||||
            <th style="width: 20%">Parent</th>
 | 
					 | 
				
			||||||
            <th style="width: auto">Manager</th>
 | 
					 | 
				
			||||||
            <th style="width: auto"> </th>
 | 
					 | 
				
			||||||
            <th style="width: auto"> </th>
 | 
					 | 
				
			||||||
        </MatTableHeader>
 | 
					 | 
				
			||||||
        <MatTableRow>
 | 
					 | 
				
			||||||
            <td>@context.CommonName</td>
 | 
					 | 
				
			||||||
            <td>@context.Description</td>
 | 
					 | 
				
			||||||
            <td>@context.Parent</td>
 | 
					 | 
				
			||||||
            <td>@context.Manager</td>
 | 
					 | 
				
			||||||
            <td>
 | 
					 | 
				
			||||||
                <a href="organizationUnits" @onclick="@(e => Edit(context))">edit</a>
 | 
					 | 
				
			||||||
            </td>
 | 
					 | 
				
			||||||
            <td>
 | 
					 | 
				
			||||||
                <a href="organizationUnits" @onclick="@(e => Delete(context))">delete</a>
 | 
					 | 
				
			||||||
            </td>
 | 
					 | 
				
			||||||
        </MatTableRow>
 | 
					 | 
				
			||||||
    </MatTable>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <MatButton @onclick="@(e => Edit(new OrganizationUnit()))">Create organization unit</MatButton>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<MatDialog @bind-IsOpen="@DialogIsOpen">
 | 
					 | 
				
			||||||
    @if (OuToEdit != null)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        <MatDialogTitle>@(OuToEdit.Id == 0 ? "New" : "Edit") @OuToEdit.CommonName (@OuToEdit.Id)</MatDialogTitle>
 | 
					 | 
				
			||||||
        <MatDialogContent>
 | 
					 | 
				
			||||||
            <MatTextField Label="Common name" @bind-Value="@OuToEdit.CommonName" ReadOnly="@(OuToEdit.Id != 0)"/>
 | 
					 | 
				
			||||||
            <p/>
 | 
					 | 
				
			||||||
            <MatTextField Label="Description" @bind-Value="@OuToEdit.Description"/>
 | 
					 | 
				
			||||||
            @*<MatTextField Label="Manager" @bind-Value="@OuToEdit.Manager"/>*@
 | 
					 | 
				
			||||||
            <p/>
 | 
					 | 
				
			||||||
            <MatSelectItem Items="@OrganizationUnits" Label="Parent" @bind-Value="@OuToEdit.Parent"/>
 | 
					 | 
				
			||||||
        </MatDialogContent>
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        <MatDialogTitle>No securityGroup selected</MatDialogTitle>
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    <MatDialogActions>
 | 
					 | 
				
			||||||
        <MatButton OnClick="@(e => { DialogIsOpen = false; })">No Thanks</MatButton>
 | 
					 | 
				
			||||||
        <MatButton OnClick="@OkClick">OK</MatButton>
 | 
					 | 
				
			||||||
    </MatDialogActions>
 | 
					 | 
				
			||||||
</MatDialog>
 | 
					 | 
				
			||||||
@@ -1,41 +0,0 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Components;
 | 
					 | 
				
			||||||
using UserService.DatabaseLayer.DataModels;
 | 
					 | 
				
			||||||
using UserService.DatabaseLayer.Repository;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace UserService.Pages
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public class OrganizationUnitsBase : ComponentBase
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        [Inject] private IOrganizationUnitsRepository OrganizationUnitsRepository { get; set; } = null!;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected bool DialogIsOpen { get; set; }
 | 
					 | 
				
			||||||
        protected OrganizationUnit? OuToEdit { get; private set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected IReadOnlyList<OrganizationUnit>? OrganizationUnits { get; private set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override async Task OnInitializedAsync()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            OrganizationUnits = await OrganizationUnitsRepository.GetAllAsync().ConfigureAwait(false);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected void Edit(OrganizationUnit organizationUnit)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            DialogIsOpen = true;
 | 
					 | 
				
			||||||
            OuToEdit = organizationUnit;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected async Task OkClick()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (OuToEdit is null) return;
 | 
					 | 
				
			||||||
            await OrganizationUnitsRepository.UpdateAsync(OuToEdit).ConfigureAwait(false);
 | 
					 | 
				
			||||||
            DialogIsOpen = false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected async Task Delete(OrganizationUnit organizationUnit)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            await OrganizationUnitsRepository.DeleteAsync(organizationUnit).ConfigureAwait(false);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,59 +1,87 @@
 | 
				
			|||||||
@page "/securitygroups"
 | 
					@page "/securitygroups"
 | 
				
			||||||
@using UserService.DatabaseLayer.DataModels
 | 
					@using UserService.Infrastructure.DataModels
 | 
				
			||||||
@using UserService.DatabaseLayer.Repository
 | 
					 | 
				
			||||||
@inherits SecurityGroupsBase
 | 
					@inherits SecurityGroupsBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<h1>Table of all security groups</h1>
 | 
					<h1>Table of all security groups</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@if (SecurityGroups is null)
 | 
					@if (Members is null)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    <p>
 | 
					<p>
 | 
				
			||||||
        <em>Loading...</em>
 | 
					    <em>Loading...</em>
 | 
				
			||||||
    </p>
 | 
					</p>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    <MatTable Items="@SecurityGroups" class="mat-elevation-z5">
 | 
					<TextEdit Placeholder="Search" Size="Size.Large" @bind-Text="@CustomFilterValue" />
 | 
				
			||||||
        <MatTableHeader>
 | 
					 | 
				
			||||||
            <th style="width: 30%">Common Name</th>
 | 
					 | 
				
			||||||
            <th style="width: 20%">Description</th>
 | 
					 | 
				
			||||||
            <th style="width: 20%">E-Mail</th>
 | 
					 | 
				
			||||||
            <th style="width: 20%">Parent</th>
 | 
					 | 
				
			||||||
            <th style="width: auto"> </th>
 | 
					 | 
				
			||||||
            <th style="width: auto"> </th>
 | 
					 | 
				
			||||||
        </MatTableHeader>
 | 
					 | 
				
			||||||
        <MatTableRow>
 | 
					 | 
				
			||||||
            <td>@context.CommonName</td>
 | 
					 | 
				
			||||||
            <td>@context.Description</td>
 | 
					 | 
				
			||||||
            <td>@context.EMail</td>
 | 
					 | 
				
			||||||
            <td>@context.Parent</td>
 | 
					 | 
				
			||||||
            <td><a href="securitygroups" @onclick="@(e => EditSecurityGroup(context))">edit</a></td>
 | 
					 | 
				
			||||||
            <td><a href="securitygroups" @onclick="@(e => DeleteSecurityGroup(context))">delete</a></td>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            </MatTableRow>
 | 
					    <DataGrid 
 | 
				
			||||||
    </MatTable>
 | 
					        TItem="SecurityGroup" 
 | 
				
			||||||
    <MatButton @onclick="@(e => EditSecurityGroup(new SecurityGroup()))">Create new group</MatButton>
 | 
					        RowSelectable="@(u => false)" 
 | 
				
			||||||
 | 
					        CustomFilter="@OnCustomFilter" 
 | 
				
			||||||
 | 
					        Sortable="true" 
 | 
				
			||||||
 | 
					        Editable="true" 
 | 
				
			||||||
 | 
					        EditMode="DataGridEditMode.Inline" 
 | 
				
			||||||
 | 
					        RowRemoving="RowDeletingCallback" 
 | 
				
			||||||
 | 
					        Data="@Members" 
 | 
				
			||||||
 | 
					        RowInserted="RowInsertedCallback" 
 | 
				
			||||||
 | 
					        RowInserting="RowInsertingCallback" 
 | 
				
			||||||
 | 
					        RowUpdating="RowUpdatingCallback">
 | 
				
			||||||
 | 
					        <DataGridCommandColumn TItem="SecurityGroup">
 | 
				
			||||||
 | 
					            <NewCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Success" Clicked="@context.Clicked" title="Create security group">
 | 
				
			||||||
 | 
					                    <i class="fas fa-users"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </NewCommandTemplate>
 | 
				
			||||||
 | 
					            <EditCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Primary" Clicked="@context.Clicked" title="Edit security group">
 | 
				
			||||||
 | 
					                    <i class="fa fa-user-edit"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </EditCommandTemplate>
 | 
				
			||||||
 | 
					            <DeleteCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Danger" Clicked="@context.Clicked" title="Delete security group">
 | 
				
			||||||
 | 
					                    <i class="fa fa-user-minus"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </DeleteCommandTemplate>
 | 
				
			||||||
 | 
					            <SaveCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Success" Clicked="@context.Clicked" title="Save security group">
 | 
				
			||||||
 | 
					                    <i class="fas fa-save"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </SaveCommandTemplate>
 | 
				
			||||||
 | 
					            <CancelCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Danger" Clicked="@context.Clicked" title="Cancel editing">
 | 
				
			||||||
 | 
					                    <i class="far fa-times-circle"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </CancelCommandTemplate>
 | 
				
			||||||
 | 
					        </DataGridCommandColumn>
 | 
				
			||||||
 | 
					        <DataGridColumn TItem="SecurityGroup" Field="@nameof(SecurityGroup.Id)" Caption="#" Sortable="false" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <DataGridColumn TItem="SecurityGroup" Field="@nameof(SecurityGroup.CommonName)" Caption="CN" CellsEditableOnEditCommand="false" Editable="true">
 | 
				
			||||||
 | 
					            <EditTemplate>
 | 
				
			||||||
 | 
					                <Validation Validator="@ValidateCommonName">
 | 
				
			||||||
 | 
					                    <TextEdit Placeholder="Enter common name" Text="@((string)(((CellEditContext)context).CellValue))" TextChanged="@(v=>((CellEditContext)context).CellValue=v)">
 | 
				
			||||||
 | 
					                        <Feedback>
 | 
				
			||||||
 | 
					                            <ValidationSuccess></ValidationSuccess>
 | 
				
			||||||
 | 
					                            <ValidationError>Please enter a valid common name!</ValidationError>
 | 
				
			||||||
 | 
					                        </Feedback>
 | 
				
			||||||
 | 
					                    </TextEdit>
 | 
				
			||||||
 | 
					                </Validation>
 | 
				
			||||||
 | 
					            </EditTemplate>
 | 
				
			||||||
 | 
					        </DataGridColumn>
 | 
				
			||||||
 | 
					        <DataGridSelectColumn TItem="SecurityGroup" Field="@nameof(SecurityGroup.ParentId)" Caption="Parent" Editable="true">
 | 
				
			||||||
 | 
					            <DisplayTemplate>
 | 
				
			||||||
 | 
					                @{
 | 
				
			||||||
 | 
					                    var name = ((SecurityGroup) context ).Parent?.CommonName ?? "-";
 | 
				
			||||||
 | 
					                    @name
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            </DisplayTemplate>
 | 
				
			||||||
 | 
					            <EditTemplate>
 | 
				
			||||||
 | 
					                    <Select TValue="int?" SelectedValue="@((int?)(context.CellValue))" SelectedValueChanged="@(v => context.CellValue = v)" >
 | 
				
			||||||
 | 
					                    @foreach (var item in OrganizationUnits ?? Enumerable.Empty<OrganizationUnit>())
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        <SelectItem TValue="int" Value="@(item.Id)">@item.CommonName</SelectItem>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    </Select>
 | 
				
			||||||
 | 
					            </EditTemplate>
 | 
				
			||||||
 | 
					        </DataGridSelectColumn>
 | 
				
			||||||
 | 
					    </DataGrid>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
<MatDialog @bind-IsOpen="@DialogIsOpen">
 | 
					 | 
				
			||||||
    @if (SecurityGroupToEdit != null)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        <MatDialogTitle>@(SecurityGroupToEdit.Id == 0 ? "New" : "Edit") @SecurityGroupToEdit.CommonName (@SecurityGroupToEdit.Id)</MatDialogTitle>
 | 
					 | 
				
			||||||
        <MatDialogContent>
 | 
					 | 
				
			||||||
            <MatTextField Label="Common name" @bind-Value="@SecurityGroupToEdit.CommonName" ReadOnly="@(SecurityGroupToEdit.Id != 0)"></MatTextField>
 | 
					 | 
				
			||||||
            <p />
 | 
					 | 
				
			||||||
            <MatTextField Label="Description" @bind-Value="@SecurityGroupToEdit.Description"></MatTextField>
 | 
					 | 
				
			||||||
            <MatTextField Label="E-Mail" @bind-Value="@SecurityGroupToEdit.EMail"></MatTextField>
 | 
					 | 
				
			||||||
            <p />
 | 
					 | 
				
			||||||
            <MatSelectItem Items="@OrganizationUnits" Label="Parent" @bind-Value="@SecurityGroupToEdit.Parent"></MatSelectItem>
 | 
					 | 
				
			||||||
        </MatDialogContent>
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        <MatDialogTitle>No securityGroup selected</MatDialogTitle>
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    <MatDialogActions>
 | 
					 | 
				
			||||||
        <MatButton OnClick="@(e => { DialogIsOpen = false; })">No Thanks</MatButton>
 | 
					 | 
				
			||||||
        <MatButton OnClick="@OkClick">OK</MatButton>
 | 
					 | 
				
			||||||
    </MatDialogActions>
 | 
					 | 
				
			||||||
</MatDialog>
 | 
					 | 
				
			||||||
@@ -1,47 +1,49 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Blazorise.DataGrid;
 | 
				
			||||||
using Microsoft.AspNetCore.Components;
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
using UserService.DatabaseLayer.DataModels;
 | 
					 | 
				
			||||||
using UserService.DatabaseLayer.Repository;
 | 
					using UserService.DatabaseLayer.Repository;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace UserService.Pages
 | 
					namespace UserService.Pages
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class SecurityGroupsBase : ComponentBase
 | 
					    public class SecurityGroupsBase : MembersBase<SecurityGroup>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        [Inject] private ISecurityGroupsRepository? SecurityGroupsRepository { get; set; }
 | 
					        [Inject] private ISecurityGroupsRepository SecurityGroupsRepository { get; set; } = null!;
 | 
				
			||||||
        [Inject] private IOrganizationUnitsRepository? OrganizationUnitsRepository { get; set; }
 | 
					        [Inject] private IOrganizationUnitsRepository OrganizationUnitsRepository { get; set; } = null!;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected bool DialogIsOpen;
 | 
					 | 
				
			||||||
        protected SecurityGroup? SecurityGroupToEdit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected IReadOnlyList<SecurityGroup>? SecurityGroups;
 | 
					 | 
				
			||||||
        protected IReadOnlyList<OrganizationUnit>? OrganizationUnits;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override async Task OnInitializedAsync()
 | 
					        protected override async Task OnInitializedAsync()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            SecurityGroups = await SecurityGroupsRepository.GetAllAsync().ConfigureAwait(false);
 | 
					            Members = await SecurityGroupsRepository.GetAllAsync().ConfigureAwait(false);
 | 
				
			||||||
            OrganizationUnits = await OrganizationUnitsRepository.GetAllAsync().ConfigureAwait(false);
 | 
					            OrganizationUnits = await OrganizationUnitsRepository.GetAllAsync().ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected void EditSecurityGroup(SecurityGroup securityGroup)
 | 
					        /// <inheritdoc />
 | 
				
			||||||
 | 
					        protected override async Task RowInsertingCallback(CancellableRowChange<SecurityGroup, Dictionary<string, object>> arg)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            SecurityGroupToEdit = securityGroup;
 | 
					 | 
				
			||||||
            DialogIsOpen = true;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected async Task OkClick()
 | 
					        /// <inheritdoc />
 | 
				
			||||||
 | 
					        protected override async Task RowInsertedCallback(SavedRowItem<SecurityGroup, Dictionary<string, object>> arg)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!(SecurityGroupToEdit is null))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                await SecurityGroupsRepository.UpdateAsync(SecurityGroupToEdit).ConfigureAwait(false);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            DialogIsOpen = false;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected async Task DeleteSecurityGroup(SecurityGroup securityGroup)
 | 
					        /// <inheritdoc />
 | 
				
			||||||
 | 
					        protected override async Task RowDeletingCallback(CancellableRowChange<SecurityGroup> arg)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await SecurityGroupsRepository.DeleteAsync(securityGroup).ConfigureAwait(false);
 | 
					            
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <inheritdoc />
 | 
				
			||||||
 | 
					        protected override async Task RowUpdatingCallback(CancellableRowChange<SecurityGroup, Dictionary<string, object>> arg)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <inheritdoc />
 | 
				
			||||||
 | 
					        protected override bool OnCustomFilter(SecurityGroup model)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
@page "/users"
 | 
					@page "/users"
 | 
				
			||||||
@using UserService.DatabaseLayer.DataModels
 | 
					@using UserService.Infrastructure.DataModels
 | 
				
			||||||
@inherits UsersBase
 | 
					@inherits UsersBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<h1>List of all users</h1>
 | 
					<h1>List of all users</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@if (Users == null)
 | 
					@if (Members == null)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    <p>
 | 
					    <p>
 | 
				
			||||||
        <em>Loading...</em>
 | 
					        <em>Loading...</em>
 | 
				
			||||||
@@ -12,55 +12,92 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    <MatTable Items="@Users" class="mat-elevation-z5">
 | 
					    <TextEdit Placeholder="Search" Size="Size.Large" @bind-Text="@CustomFilterValue" />
 | 
				
			||||||
        <MatTableHeader>
 | 
					 | 
				
			||||||
            <th style="width: 20%">Common Name</th>
 | 
					 | 
				
			||||||
            <th style="width: 30%">Full name</th>
 | 
					 | 
				
			||||||
            <th style="width: 20%">Description</th>
 | 
					 | 
				
			||||||
            <th style="width: 20%">E-Mail</th>
 | 
					 | 
				
			||||||
            <th style="width: 20%">Parent</th>
 | 
					 | 
				
			||||||
            <th style="width: auto">Is active</th>
 | 
					 | 
				
			||||||
            <th style="width: auto"> </th>
 | 
					 | 
				
			||||||
            <th style="width: auto"> </th>
 | 
					 | 
				
			||||||
        </MatTableHeader>
 | 
					 | 
				
			||||||
        <MatTableRow>
 | 
					 | 
				
			||||||
            <td>@context.CommonName</td>
 | 
					 | 
				
			||||||
            <td>@context.FullName</td>
 | 
					 | 
				
			||||||
            <td>@context.Description</td>
 | 
					 | 
				
			||||||
            <td>@context.EMail</td>
 | 
					 | 
				
			||||||
            <td>@context.Parent</td>
 | 
					 | 
				
			||||||
            <td>@context.IsActive</td>
 | 
					 | 
				
			||||||
            <td><a href="users" @onclick="@(e => EditUser(context))">edit</a></td>
 | 
					 | 
				
			||||||
            <td><a href="users" @onclick="@(e => DeleteUser(context))">delete</a></td>
 | 
					 | 
				
			||||||
        </MatTableRow>
 | 
					 | 
				
			||||||
    </MatTable>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <MatButton @onclick="@(e => EditUser(new User()))">Create user</MatButton>
 | 
					    <DataGrid 
 | 
				
			||||||
 | 
					        TItem="User" 
 | 
				
			||||||
 | 
					        RowSelectable="@(u => false)" 
 | 
				
			||||||
 | 
					        CustomFilter="@OnCustomFilter" 
 | 
				
			||||||
 | 
					        Sortable="true" 
 | 
				
			||||||
 | 
					        Editable="true" 
 | 
				
			||||||
 | 
					        EditMode="DataGridEditMode.Inline" 
 | 
				
			||||||
 | 
					        RowRemoving="RowDeletingCallback" 
 | 
				
			||||||
 | 
					        Data="@Members" 
 | 
				
			||||||
 | 
					        RowInserted="RowInsertedCallback" 
 | 
				
			||||||
 | 
					        RowInserting="RowInsertingCallback" 
 | 
				
			||||||
 | 
					        RowUpdating="RowUpdatingCallback">
 | 
				
			||||||
 | 
					        <DataGridCommandColumn TItem="User">
 | 
				
			||||||
 | 
					            <NewCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Success" Clicked="@context.Clicked" title="Create user">
 | 
				
			||||||
 | 
					                    <i class="fa fa-user-plus"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </NewCommandTemplate>
 | 
				
			||||||
 | 
					            <EditCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Primary" Clicked="@context.Clicked" title="Edit user">
 | 
				
			||||||
 | 
					                    <i class="fa fa-user-edit"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </EditCommandTemplate>
 | 
				
			||||||
 | 
					            <DeleteCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Danger" Clicked="@context.Clicked" title="Delete user">
 | 
				
			||||||
 | 
					                    <i class="fa fa-user-minus"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </DeleteCommandTemplate>
 | 
				
			||||||
 | 
					            <SaveCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Success" Clicked="@context.Clicked" title="Save user">
 | 
				
			||||||
 | 
					                    <i class="fas fa-save"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </SaveCommandTemplate>
 | 
				
			||||||
 | 
					            <CancelCommandTemplate>
 | 
				
			||||||
 | 
					                <Button Color="Color.Danger" Clicked="@context.Clicked" title="Cancel editing">
 | 
				
			||||||
 | 
					                    <i class="far fa-times-circle"></i>
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </CancelCommandTemplate>
 | 
				
			||||||
 | 
					        </DataGridCommandColumn>
 | 
				
			||||||
 | 
					        <DataGridColumn TItem="User" Field="@nameof(User.Id)" Caption="#" Sortable="false" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <DataGridColumn TItem="User" Field="@nameof(User.CommonName)" Caption="CN" CellsEditableOnEditCommand="false" Editable="true">
 | 
				
			||||||
 | 
					            <EditTemplate>
 | 
				
			||||||
 | 
					                <Validation Validator="@ValidateCommonName">
 | 
				
			||||||
 | 
					                    <TextEdit Placeholder="Enter common name" Text="@((string)(((CellEditContext)context).CellValue))" TextChanged="@(v=>((CellEditContext)context).CellValue=v)">
 | 
				
			||||||
 | 
					                        <Feedback>
 | 
				
			||||||
 | 
					                            <ValidationSuccess></ValidationSuccess>
 | 
				
			||||||
 | 
					                            <ValidationError>Please enter a valid common name!</ValidationError>
 | 
				
			||||||
 | 
					                        </Feedback>
 | 
				
			||||||
 | 
					                    </TextEdit>
 | 
				
			||||||
 | 
					                </Validation>
 | 
				
			||||||
 | 
					            </EditTemplate>
 | 
				
			||||||
 | 
					        </DataGridColumn>
 | 
				
			||||||
 | 
					        <DataGridColumn TItem="User" Field="@nameof(User.FirstName)" Caption="First Name" Editable="true" />
 | 
				
			||||||
 | 
					        <DataGridColumn TItem="User" Field="@nameof(User.LastName)" Caption="Last Name" Editable="true"/>
 | 
				
			||||||
 | 
					        <DataGridColumn TItem="User" Field="@nameof(User.EMail)" Caption="EMail" Editable="true">
 | 
				
			||||||
 | 
					            <EditTemplate>
 | 
				
			||||||
 | 
					                <Validation Validator="@ValidateEmail">
 | 
				
			||||||
 | 
					                    <TextEdit Placeholder="Enter email" Text="@((string)(((CellEditContext)context).CellValue))" TextChanged="@(v=>((CellEditContext)context).CellValue=v)">
 | 
				
			||||||
 | 
					                        <Feedback>
 | 
				
			||||||
 | 
					                            <ValidationNone>Please enter the email.</ValidationNone>
 | 
				
			||||||
 | 
					                            <ValidationSuccess>Email is ok.</ValidationSuccess>
 | 
				
			||||||
 | 
					                            <ValidationError>Enter valid email!</ValidationError>
 | 
				
			||||||
 | 
					                        </Feedback>
 | 
				
			||||||
 | 
					                    </TextEdit>
 | 
				
			||||||
 | 
					                </Validation>
 | 
				
			||||||
 | 
					            </EditTemplate>
 | 
				
			||||||
 | 
					        </DataGridColumn>
 | 
				
			||||||
 | 
					        <DataGridSelectColumn TItem="User" Field="@nameof(User.ParentId)" Caption="Parent" Editable="true">
 | 
				
			||||||
 | 
					            <DisplayTemplate>
 | 
				
			||||||
 | 
					                @{
 | 
				
			||||||
 | 
					                    var name = ((User) context ).Parent?.CommonName ?? "-";
 | 
				
			||||||
 | 
					                    @name
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            </DisplayTemplate>
 | 
				
			||||||
 | 
					            <EditTemplate>
 | 
				
			||||||
 | 
					                    <Select TValue="int?" SelectedValue="@((int?)(context.CellValue))" SelectedValueChanged="@(v => context.CellValue = v)" >
 | 
				
			||||||
 | 
					                    @foreach (var item in OrganizationUnits ?? Enumerable.Empty<OrganizationUnit>())
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        <SelectItem TValue="int" Value="@(item.Id)">@item.CommonName</SelectItem>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    </Select>
 | 
				
			||||||
 | 
					            </EditTemplate>
 | 
				
			||||||
 | 
					        </DataGridSelectColumn>
 | 
				
			||||||
 | 
					        <DataGridCheckColumn TItem="User" Field="@nameof(User.IsActive)" Caption="Active" Editable="true" />
 | 
				
			||||||
 | 
					    </DataGrid>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
<MatDialog @bind-IsOpen="@DialogIsOpen">
 | 
					 | 
				
			||||||
    @if (UserToEdit != null)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        <MatDialogTitle>@(UserToEdit.Id == 0 ? "New" : "Edit") @UserToEdit.CommonName (@UserToEdit.Id)</MatDialogTitle>
 | 
					 | 
				
			||||||
        <MatDialogContent>
 | 
					 | 
				
			||||||
            <MatTextField Label="Common name" @bind-Value="@UserToEdit.CommonName" ReadOnly="@(UserToEdit.Id != 0)" />
 | 
					 | 
				
			||||||
            <MatSlideToggle Label="Is active" @bind-Value="@UserToEdit.IsActive" />
 | 
					 | 
				
			||||||
            <p />
 | 
					 | 
				
			||||||
            <MatTextField Label="First name" @bind-Value="@UserToEdit.FirstName" />
 | 
					 | 
				
			||||||
            <MatTextField Label="Last name" @bind-Value="@UserToEdit.LastName" />
 | 
					 | 
				
			||||||
            <p />
 | 
					 | 
				
			||||||
            <MatTextField Label="Description" @bind-Value="@UserToEdit.Description" />
 | 
					 | 
				
			||||||
            <MatTextField Label="E-Mail" @bind-Value="@UserToEdit.EMail" />
 | 
					 | 
				
			||||||
            <p />
 | 
					 | 
				
			||||||
            <MatSelectItem  Items="@OrganizationUnits" TItem="Node" Label="Parent" @bind-Value="@UserToEdit.Parent" />
 | 
					 | 
				
			||||||
        </MatDialogContent>
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        <MatDialogTitle>No securityGroup selected</MatDialogTitle>
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    <MatDialogActions>
 | 
					 | 
				
			||||||
        <MatButton OnClick="@(e => { DialogIsOpen = false; })">No Thanks</MatButton>
 | 
					 | 
				
			||||||
        <MatButton OnClick="@OkClick">OK</MatButton>
 | 
					 | 
				
			||||||
    </MatDialogActions>
 | 
					 | 
				
			||||||
</MatDialog>
 | 
					 | 
				
			||||||
@@ -1,44 +1,99 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Components;
 | 
					using Microsoft.AspNetCore.Components;
 | 
				
			||||||
using UserService.DatabaseLayer.DataModels;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Blazorise;
 | 
				
			||||||
 | 
					using Blazorise.DataGrid;
 | 
				
			||||||
 | 
					using Microsoft.JSInterop;
 | 
				
			||||||
using UserService.DatabaseLayer.Repository;
 | 
					using UserService.DatabaseLayer.Repository;
 | 
				
			||||||
 | 
					using UserService.Infrastructure;
 | 
				
			||||||
 | 
					using UserService.Infrastructure.DataModels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace UserService.Pages
 | 
					namespace UserService.Pages
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class UsersBase : ComponentBase
 | 
					    public class UsersBase : MembersBase<User>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        [Inject] private IUsersRepository UsersRepository { get; set; } = null!;
 | 
					        [Inject] private IUsersRepository UsersRepository { get; set; } = null!;
 | 
				
			||||||
        [Inject] private IOrganizationUnitsRepository OrganizationUnitsRepository { get; set; } = null!;
 | 
					        [Inject] private IOrganizationUnitsRepository OrganizationUnitsRepository { get; set; } = null!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected bool DialogIsOpen { get; set; }
 | 
					        [Inject] private IJSRuntime JsRuntime { get; set; } = null!;
 | 
				
			||||||
        protected User? UserToEdit { get; private set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected IReadOnlyList<User>? Users { get; private set; }
 | 
					 | 
				
			||||||
        protected IReadOnlyList<OrganizationUnit>? OrganizationUnits { get; private set; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override async Task OnInitializedAsync()
 | 
					        protected override async Task OnInitializedAsync()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Users = await UsersRepository.GetAllAsync();
 | 
					            Members = await UsersRepository.GetAllAsync().ConfigureAwait(false);
 | 
				
			||||||
            OrganizationUnits = await OrganizationUnitsRepository.GetAllAsync().ConfigureAwait(false);
 | 
					            OrganizationUnits = await OrganizationUnitsRepository.GetAllAsync().ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected void EditUser(User user)
 | 
					        protected override async Task RowInsertingCallback(CancellableRowChange<User, Dictionary<string, object>> arg)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            DialogIsOpen = true;
 | 
					            if (arg is null) throw new ArgumentNullException(nameof(arg));
 | 
				
			||||||
            UserToEdit = user;
 | 
					            var mailValidation = Validators.ValidateEmail(arg.Values[nameof(User.EMail)]?.ToString());
 | 
				
			||||||
 | 
					            var commonNameValidation = Validators.ValidateCommonName(arg.Values[nameof(User.CommonName)]?.ToString(),
 | 
				
			||||||
 | 
					                Members ?? Enumerable.Empty<User>());
 | 
				
			||||||
 | 
					            if (mailValidation == true && commonNameValidation == true) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await JsRuntime.InvokeVoidAsync("alert", "User could not be added").ConfigureAwait(false);
 | 
				
			||||||
 | 
					            arg.Cancel = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected async Task OkClick()
 | 
					        protected override async Task RowInsertedCallback(SavedRowItem<User, Dictionary<string, object>> arg)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (UserToEdit is null) return;
 | 
					            if (arg is null) throw new ArgumentNullException(nameof(arg));
 | 
				
			||||||
            await UsersRepository.UpdateAsync(UserToEdit).ConfigureAwait(false);
 | 
					            var user = arg.Item;
 | 
				
			||||||
            DialogIsOpen = false;
 | 
					            await UsersRepository.AddAsync(user).ConfigureAwait(false);
 | 
				
			||||||
 | 
					            user.Parent = OrganizationUnits?.FirstOrDefault(x => x.Id == user.ParentId);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected async Task DeleteUser(User user)
 | 
					        protected override async Task RowDeletingCallback(CancellableRowChange<User> arg)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            await UsersRepository.DeleteAsync(user).ConfigureAwait(false);
 | 
					            if (arg == null) throw new ArgumentNullException(nameof(arg));
 | 
				
			||||||
 | 
					            var confirmed = await JsRuntime.InvokeAsync<bool>("confirm",
 | 
				
			||||||
 | 
					                $"You are about to delete the user {arg.Item.FullName}. Are you sure?").ConfigureAwait(false);
 | 
				
			||||||
 | 
					            if (confirmed)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await UsersRepository.DeleteAsync(arg.Item).ConfigureAwait(false);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            arg.Cancel = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected static void ValidateEmail(ValidatorEventArgs e)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (e == null) throw new ArgumentNullException(nameof(e));
 | 
				
			||||||
 | 
					            var email = e.Value?.ToString();
 | 
				
			||||||
 | 
					            var validationResult = Validators.ValidateEmail(email);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            e.Status = validationResult switch
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                null => ValidationStatus.None,
 | 
				
			||||||
 | 
					                false => ValidationStatus.Error,
 | 
				
			||||||
 | 
					                _ => ValidationStatus.Success
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override async Task RowUpdatingCallback(CancellableRowChange<User, Dictionary<string, object>> arg)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (arg == null) throw new ArgumentNullException(nameof(arg));
 | 
				
			||||||
 | 
					            var user = arg.Item;
 | 
				
			||||||
 | 
					            user.MapFields(arg.Values);
 | 
				
			||||||
 | 
					            user.Parent = OrganizationUnits?.FirstOrDefault(x => x.Id == (int?) arg.Values[nameof(Node.ParentId)]);
 | 
				
			||||||
 | 
					            var result = await UsersRepository.UpdateAsync(user).ConfigureAwait(false);
 | 
				
			||||||
 | 
					            arg.Cancel = !result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override bool OnCustomFilter(User model)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (model == null) throw new ArgumentNullException(nameof(model));
 | 
				
			||||||
 | 
					            // We want to accept empty value as valid or otherwise
 | 
				
			||||||
 | 
					            // datagrid will not show anything.
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(CustomFilterValue) || CustomFilterValue.Length < 3) return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					                model.FirstName?.Contains(CustomFilterValue, StringComparison.OrdinalIgnoreCase) == true
 | 
				
			||||||
 | 
					                || model.LastName?.Contains(CustomFilterValue, StringComparison.OrdinalIgnoreCase) == true
 | 
				
			||||||
 | 
					                || model.CommonName.Contains(CustomFilterValue, StringComparison.OrdinalIgnoreCase);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -8,33 +8,41 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					<!DOCTYPE html>
 | 
				
			||||||
<html lang="en">
 | 
					<html lang="en">
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
    <meta charset="utf-8"/>
 | 
					    <meta charset="utf-8" />
 | 
				
			||||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
				
			||||||
    <title>UserService</title>
 | 
					    <title>UserService</title>
 | 
				
			||||||
    <base href="~/"/>
 | 
					    <base href="~/" />
 | 
				
			||||||
 | 
					    <link href="css/site.css" rel="stylesheet" />
 | 
				
			||||||
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
 | 
					    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
 | 
				
			||||||
    <link href="css/site.css" rel="stylesheet"/>
 | 
					    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.0/css/all.css">
 | 
				
			||||||
    <script src="_content/MatBlazor/dist/matBlazor.js"></script>
 | 
					
 | 
				
			||||||
    <link href="_content/MatBlazor/dist/matBlazor.css" rel="stylesheet"/>
 | 
					    <link href="_content/Blazorise/blazorise.css" rel="stylesheet" />
 | 
				
			||||||
 | 
					    <link href="_content/Blazorise.Bootstrap/blazorise.bootstrap.css" rel="stylesheet" />
 | 
				
			||||||
 | 
					    <link href="_content/Blazorise.Sidebar/blazorise.sidebar.css" rel="stylesheet" />
 | 
				
			||||||
 | 
					    <link href="_content/Blazorise.TreeView/blazorise.treeview.css" rel="stylesheet" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
<app>
 | 
					    <app>
 | 
				
			||||||
    <component type="typeof(App)" render-mode="ServerPrerendered"/>
 | 
					        <component type="typeof(App)" render-mode="ServerPrerendered" />
 | 
				
			||||||
</app>
 | 
					    </app>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div id="blazor-error-ui">
 | 
					    <div id="blazor-error-ui">
 | 
				
			||||||
    <environment include="Staging,Production">
 | 
					        <environment include="Staging,Production">
 | 
				
			||||||
        An error has occurred. This application may no longer respond until reloaded.
 | 
					            An error has occurred. This application may no longer respond until reloaded.
 | 
				
			||||||
    </environment>
 | 
					        </environment>
 | 
				
			||||||
    <environment include="Development">
 | 
					        <environment include="Development">
 | 
				
			||||||
        An unhandled exception has occurred. See browser dev tools for details.
 | 
					            An unhandled exception has occurred. See browser dev tools for details.
 | 
				
			||||||
    </environment>
 | 
					        </environment>
 | 
				
			||||||
    <a href="" class="reload">Reload</a>
 | 
					        <a href="" class="reload">Reload</a>
 | 
				
			||||||
    <a class="dismiss">🗙</a>
 | 
					        <a class="dismiss">🗙</a>
 | 
				
			||||||
</div>
 | 
					    </div>
 | 
				
			||||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
 | 
					    <script src="_framework/blazor.server.js"></script>
 | 
				
			||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
 | 
					    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
 | 
				
			||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
 | 
					    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
 | 
				
			||||||
<script src="_framework/blazor.server.js"></script>
 | 
					    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <script src="_content/Blazorise/blazorise.js"></script>
 | 
				
			||||||
 | 
					    <script src="_content/Blazorise.Bootstrap/blazorise.bootstrap.js"></script>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
@@ -1,49 +1,38 @@
 | 
				
			|||||||
<div class="top-row pl-4 navbar navbar-dark">
 | 
					<Sidebar Data="@_sidebarInfo" />
 | 
				
			||||||
    <a class="navbar-brand" href="">UserService</a>
 | 
					 | 
				
			||||||
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
 | 
					 | 
				
			||||||
        <span class="navbar-toggler-icon"></span>
 | 
					 | 
				
			||||||
    </button>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
 | 
					 | 
				
			||||||
    <ul class="nav flex-column">
 | 
					 | 
				
			||||||
        <li class="nav-item px-3">
 | 
					 | 
				
			||||||
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
 | 
					 | 
				
			||||||
                <span class="oi oi-home" aria-hidden="true"></span> Home
 | 
					 | 
				
			||||||
            </NavLink>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li class="nav-item px-3">
 | 
					 | 
				
			||||||
            <NavLink class="nav-link" href="users">
 | 
					 | 
				
			||||||
                <span class="oi oi-plus" aria-hidden="true"></span> Users
 | 
					 | 
				
			||||||
            </NavLink>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li class="nav-item px-3">
 | 
					 | 
				
			||||||
            <NavLink class="nav-link" href="securitygroups">
 | 
					 | 
				
			||||||
                <span class="oi oi-plus" aria-hidden="true"></span> Security groups
 | 
					 | 
				
			||||||
            </NavLink>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li class="nav-item px-3">
 | 
					 | 
				
			||||||
            <NavLink class="nav-link" href="organizationUnits">
 | 
					 | 
				
			||||||
                <span class="oi oi-plus" aria-hidden="true"></span> Organization units
 | 
					 | 
				
			||||||
            </NavLink>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
        <li class="nav-item px-3">
 | 
					 | 
				
			||||||
            <NavLink class="nav-link" href="directory">
 | 
					 | 
				
			||||||
                <span class="oi oi-plus" aria-hidden="true"></span> Directory
 | 
					 | 
				
			||||||
            </NavLink>
 | 
					 | 
				
			||||||
        </li>
 | 
					 | 
				
			||||||
    </ul>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@code {
 | 
					@code {
 | 
				
			||||||
    private bool _collapseNavMenu = true;
 | 
					    private SidebarInfo _sidebarInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private string NavMenuCssClass => _collapseNavMenu ? "collapse" : null;
 | 
					    protected override void OnInitialized()
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void ToggleNavMenu()
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _collapseNavMenu = !_collapseNavMenu;
 | 
					        _sidebarInfo = new SidebarInfo
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Brand = new SidebarBrandInfo
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Text = "User service",
 | 
				
			||||||
 | 
					                To = "/"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Items = new List<SidebarItemInfo>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new SidebarItemInfo
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Text = "Directory",
 | 
				
			||||||
 | 
					                    Icon = IconName.Folder,
 | 
				
			||||||
 | 
					                    To = "/directory"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                new SidebarItemInfo
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Text = "Users",
 | 
				
			||||||
 | 
					                    Icon = IconName.Users,
 | 
				
			||||||
 | 
					                    To = "/users"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                new SidebarItemInfo
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Text = "Security groups",
 | 
				
			||||||
 | 
					                    Icon = IconName.Book,
 | 
				
			||||||
 | 
					                    To = "/securitygroups"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
<div class="alert alert-secondary mt-4" role="alert">
 | 
					 | 
				
			||||||
    <span class="oi oi-pencil mr-2" aria-hidden="true"></span>
 | 
					 | 
				
			||||||
    <strong>@Title</strong>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <span class="text-nowrap">
 | 
					 | 
				
			||||||
        Please take our
 | 
					 | 
				
			||||||
        <a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2112271">brief survey</a>
 | 
					 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
    and tell us what you think.
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@code {
 | 
					 | 
				
			||||||
    // Demonstrates how a parent component can supply parameters
 | 
					 | 
				
			||||||
    [Parameter]
 | 
					 | 
				
			||||||
    public string Title { get; set; }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,4 +1,7 @@
 | 
				
			|||||||
using System.Net.Http;
 | 
					using System;
 | 
				
			||||||
 | 
					using Blazorise;
 | 
				
			||||||
 | 
					using Blazorise.Bootstrap;
 | 
				
			||||||
 | 
					using Blazorise.Icons.FontAwesome;
 | 
				
			||||||
using Microsoft.AspNetCore.Builder;
 | 
					using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
using Microsoft.AspNetCore.Hosting;
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
using Microsoft.Extensions.Configuration;
 | 
					using Microsoft.Extensions.Configuration;
 | 
				
			||||||
@@ -26,12 +29,19 @@ namespace UserService
 | 
				
			|||||||
            services.AddSingleton<IUsersRepository, UsersRepository>();
 | 
					            services.AddSingleton<IUsersRepository, UsersRepository>();
 | 
				
			||||||
            services.AddSingleton<ISecurityGroupsRepository, SecurityGroupsRepository>();
 | 
					            services.AddSingleton<ISecurityGroupsRepository, SecurityGroupsRepository>();
 | 
				
			||||||
            services.AddSingleton<IOrganizationUnitsRepository, OrganizationUnitsRepository>();
 | 
					            services.AddSingleton<IOrganizationUnitsRepository, OrganizationUnitsRepository>();
 | 
				
			||||||
            services.AddScoped<HttpClient>();
 | 
					            services
 | 
				
			||||||
 | 
					                .AddBlazorise(options =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    options.ChangeTextOnKeyPress = true; // optional
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .AddBootstrapProviders()
 | 
				
			||||||
 | 
					                .AddFontAwesomeIcons();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
 | 
					        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
 | 
				
			||||||
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 | 
					        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if (app == null) throw new ArgumentNullException(nameof(app));
 | 
				
			||||||
            if (env.IsDevelopment())
 | 
					            if (env.IsDevelopment())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                app.UseDeveloperExceptionPage();
 | 
					                app.UseDeveloperExceptionPage();
 | 
				
			||||||
@@ -48,6 +58,10 @@ namespace UserService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            app.UseRouting();
 | 
					            app.UseRouting();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            app.ApplicationServices
 | 
				
			||||||
 | 
					                .UseBootstrapProviders()
 | 
				
			||||||
 | 
					                .UseFontAwesomeIcons();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            app.UseEndpoints(endpoints =>
 | 
					            app.UseEndpoints(endpoints =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                endpoints.MapBlazorHub();
 | 
					                endpoints.MapBlazorHub();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,14 +3,28 @@
 | 
				
			|||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
					    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
				
			||||||
    <Nullable>enable</Nullable>
 | 
					    <Nullable>enable</Nullable>
 | 
				
			||||||
 | 
					    <LangVersion>latest</LangVersion>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <PackageReference Include="MatBlazor" Version="2.6.2" />
 | 
					    <None Include="..\.editorconfig" Link=".editorconfig" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <ProjectReference Include="..\UserService.DatabaseLayer\UserService.DatabaseLayer.csproj" />
 | 
					    <ProjectReference Include="..\UserService.DatabaseLayer\UserService.DatabaseLayer.csproj" />
 | 
				
			||||||
 | 
					    <ProjectReference Include="..\UserService.Infrastructure\UserService.Infrastructure.csproj" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <PackageReference Include="Blazorise.Bootstrap" Version="0.9.1.2" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Blazorise.DataGrid" Version="0.9.1.2" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.1.2" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Blazorise.Sidebar" Version="0.9.1.2" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Blazorise.TreeView" Version="0.9.1.2" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
 | 
				
			||||||
 | 
					      <PrivateAssets>all</PrivateAssets>
 | 
				
			||||||
 | 
					      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
				
			||||||
 | 
					    </PackageReference>
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,4 +7,7 @@
 | 
				
			|||||||
@using Microsoft.JSInterop
 | 
					@using Microsoft.JSInterop
 | 
				
			||||||
@using UserService
 | 
					@using UserService
 | 
				
			||||||
@using UserService.Shared
 | 
					@using UserService.Shared
 | 
				
			||||||
@using MatBlazor
 | 
					@using Blazorise
 | 
				
			||||||
 | 
					@using Blazorise.Sidebar
 | 
				
			||||||
 | 
					@using Blazorise.TreeView
 | 
				
			||||||
 | 
					@using Blazorise.DataGrid
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user