Merge pull request 'Blazorise' (#4) from Blazorise into main
Reviewed-on: #4
This commit is contained in:
commit
e6822e0491
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 UserService.Infrastructure.DataModels;
|
||||
|
||||
namespace UserService.DatabaseLayer.DataModels
|
||||
{
|
||||
@ -7,6 +9,7 @@ namespace UserService.DatabaseLayer.DataModels
|
||||
{
|
||||
public static void Seed(this ModelBuilder modelBuilder)
|
||||
{
|
||||
if (modelBuilder == null) throw new ArgumentNullException(nameof(modelBuilder));
|
||||
var groups = new OrganizationUnit { CommonName = "Groups", Id = -1 };
|
||||
var users = new OrganizationUnit { CommonName = "Users", Id = -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 france = new OrganizationUnit{CommonName = "France" , Id = -3, ParentId = -2 };
|
||||
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);
|
||||
var secGroup = new SecurityGroup { CommonName = "Global Admin", Id = -8, ParentId = groups.Id };
|
||||
modelBuilder.Entity<SecurityGroup>().HasData(secGroup);
|
||||
@ -25,6 +28,7 @@ namespace UserService.DatabaseLayer.DataModels
|
||||
|
||||
public static void CreateRelations(this ModelBuilder modelBuilder)
|
||||
{
|
||||
if (modelBuilder == null) throw new ArgumentNullException(nameof(modelBuilder));
|
||||
modelBuilder.Entity<UserMember>()
|
||||
.HasKey(bc => new { bc.MemberId, bc.UserId });
|
||||
modelBuilder.Entity<UserMember>()
|
||||
@ -35,7 +39,6 @@ namespace UserService.DatabaseLayer.DataModels
|
||||
.HasOne(bc => bc.Member)
|
||||
.WithMany(c => c!.Members)
|
||||
.HasForeignKey(bc => bc.MemberId);
|
||||
|
||||
modelBuilder.Entity<Node>()
|
||||
.HasMany(c => c.Children)
|
||||
.WithOne(e => e.Parent!)
|
||||
@ -47,6 +50,7 @@ namespace UserService.DatabaseLayer.DataModels
|
||||
{
|
||||
public static IEnumerable<SecurityGroup> GetSecurityGroups(this User user)
|
||||
{
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
foreach (var userMember in user.MemberOf)
|
||||
{
|
||||
if (userMember.Member is SecurityGroup securityGroup)
|
||||
@ -62,6 +66,7 @@ namespace UserService.DatabaseLayer.DataModels
|
||||
{
|
||||
public static IEnumerable<User> GetUsers(this SecurityGroup securityGroup)
|
||||
{
|
||||
if (securityGroup == null) throw new ArgumentNullException(nameof(securityGroup));
|
||||
foreach (var userMember in securityGroup.Members)
|
||||
{
|
||||
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 UserService.Infrastructure.DataModels;
|
||||
|
||||
namespace UserService.DatabaseLayer.DataModels
|
||||
{
|
||||
|
@ -9,16 +9,16 @@ using UserService.DatabaseLayer.DataModels;
|
||||
namespace UserService.DatabaseLayer.Migrations
|
||||
{
|
||||
[DbContext(typeof(UserServiceDbContext))]
|
||||
[Migration("20200725195658_initial")]
|
||||
partial class initial
|
||||
[Migration("20200821193933_InitialCreate")]
|
||||
partial class InitialCreate
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
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")
|
||||
.ValueGeneratedOnAdd()
|
||||
@ -47,7 +47,7 @@ namespace UserService.DatabaseLayer.Migrations
|
||||
b.HasDiscriminator<string>("Discriminator").HasValue("Node");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("UserService.DatabaseLayer.DataModels.UserMember", b =>
|
||||
modelBuilder.Entity("UserService.Infrastructure.DataModels.UserMember", b =>
|
||||
{
|
||||
b.Property<int>("MemberId")
|
||||
.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")
|
||||
.HasColumnType("TEXT");
|
||||
@ -79,9 +79,9 @@ namespace UserService.DatabaseLayer.Migrations
|
||||
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")
|
||||
.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");
|
||||
|
||||
@ -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")
|
||||
.HasColumnType("TEXT");
|
||||
@ -162,36 +162,36 @@ namespace UserService.DatabaseLayer.Migrations
|
||||
{
|
||||
Id = -7,
|
||||
CommonName = "holger",
|
||||
ParentId = -6,
|
||||
ParentId = -2,
|
||||
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")
|
||||
.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")
|
||||
.HasForeignKey("MemberId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("UserService.DatabaseLayer.DataModels.User", "User")
|
||||
b.HasOne("UserService.Infrastructure.DataModels.User", "User")
|
||||
.WithMany("MemberOf")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.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()
|
||||
.HasForeignKey("ManagerId");
|
||||
});
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace UserService.DatabaseLayer.Migrations
|
||||
{
|
||||
public partial class initial : Migration
|
||||
public partial class InitialCreate : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
@ -90,13 +90,13 @@ namespace UserService.DatabaseLayer.Migrations
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "Node",
|
||||
columns: new[] { "Id", "CommonName", "Description", "Discriminator", "ParentId", "EMail" },
|
||||
values: new object[] { -8, "Global Admin", null, "SecurityGroup", -1, null });
|
||||
columns: new[] { "Id", "CommonName", "Description", "Discriminator", "ParentId", "EMail", "FirstName", "IsActive", "LastName" },
|
||||
values: new object[] { -7, "holger", null, "User", -2, null, null, true, null });
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "Node",
|
||||
columns: new[] { "Id", "CommonName", "Description", "Discriminator", "ParentId", "EMail", "FirstName", "IsActive", "LastName" },
|
||||
values: new object[] { -7, "holger", null, "User", -6, null, null, true, null });
|
||||
columns: new[] { "Id", "CommonName", "Description", "Discriminator", "ParentId", "EMail" },
|
||||
values: new object[] { -8, "Global Admin", null, "SecurityGroup", -1, null });
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "Node",
|
@ -14,9 +14,9 @@ namespace UserService.DatabaseLayer.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
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")
|
||||
.ValueGeneratedOnAdd()
|
||||
@ -45,7 +45,7 @@ namespace UserService.DatabaseLayer.Migrations
|
||||
b.HasDiscriminator<string>("Discriminator").HasValue("Node");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("UserService.DatabaseLayer.DataModels.UserMember", b =>
|
||||
modelBuilder.Entity("UserService.Infrastructure.DataModels.UserMember", b =>
|
||||
{
|
||||
b.Property<int>("MemberId")
|
||||
.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")
|
||||
.HasColumnType("TEXT");
|
||||
@ -77,9 +77,9 @@ namespace UserService.DatabaseLayer.Migrations
|
||||
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")
|
||||
.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");
|
||||
|
||||
@ -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")
|
||||
.HasColumnType("TEXT");
|
||||
@ -160,36 +160,36 @@ namespace UserService.DatabaseLayer.Migrations
|
||||
{
|
||||
Id = -7,
|
||||
CommonName = "holger",
|
||||
ParentId = -6,
|
||||
ParentId = -2,
|
||||
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")
|
||||
.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")
|
||||
.HasForeignKey("MemberId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("UserService.DatabaseLayer.DataModels.User", "User")
|
||||
b.HasOne("UserService.Infrastructure.DataModels.User", "User")
|
||||
.WithMany("MemberOf")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.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()
|
||||
.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.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using UserService.DatabaseLayer.DataModels;
|
||||
using UserService.Infrastructure.DataModels;
|
||||
|
||||
namespace UserService.DatabaseLayer.Repository
|
||||
{
|
||||
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)
|
||||
{
|
||||
_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();
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
await using var db = new UserServiceDbContext();
|
||||
await _context(db).AddAsync(@entity, token);
|
||||
await db.SaveChangesAsync(token);
|
||||
await Context(db).AddAsync(@entity, token).ConfigureAwait(false);
|
||||
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();
|
||||
_context(db).Update(entity);
|
||||
await db.SaveChangesAsync(token);
|
||||
Context(db).Update(entity);
|
||||
var items= await db.SaveChangesAsync(token).ConfigureAwait(false);
|
||||
return items > 0;
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(T entity, CancellationToken token = default)
|
||||
{
|
||||
await using var db = new UserServiceDbContext();
|
||||
_context(db).Remove(entity);
|
||||
await db.SaveChangesAsync(token);
|
||||
Context(db).Remove(entity);
|
||||
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,19 @@
|
||||
using System;
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UserService.DatabaseLayer.DataModels;
|
||||
using UserService.Infrastructure.DataModels;
|
||||
|
||||
namespace UserService.DatabaseLayer.Repository
|
||||
{
|
||||
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 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);
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<LangVersion>8</LangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.6">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</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>
|
||||
|
||||
</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 NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UserService.DatabaseLayer.DataModels;
|
||||
using UserService.Infrastructure.DataModels;
|
||||
|
||||
namespace UserService.Test
|
||||
{
|
||||
@ -21,10 +20,10 @@ namespace UserService.Test
|
||||
public async Task Test1()
|
||||
{
|
||||
await using var db = new UserServiceDbContext();
|
||||
var user = await db.Users.FirstOrDefaultAsync();
|
||||
var secGroup = await db.SecurityGroups.FirstOrDefaultAsync();
|
||||
var ous = await db.OrganizationUnits.ToListAsync();
|
||||
var mo = await db.UserMembers.ToListAsync();
|
||||
var user = await db.Users.FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
var secGroup = await db.SecurityGroups.FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
var ous = await db.OrganizationUnits.ToListAsync().ConfigureAwait(false);
|
||||
var mo = await db.UserMembers.ToListAsync().ConfigureAwait(false);
|
||||
|
||||
var securityGroupsOfUser = user.GetSecurityGroups();
|
||||
var usersOfSecurityGroup = secGroup.GetUsers();
|
||||
@ -40,12 +39,11 @@ namespace UserService.Test
|
||||
public async Task Test2()
|
||||
{
|
||||
await using var db = new UserServiceDbContext();
|
||||
var ous = await db.OrganizationUnits.ToListAsync();
|
||||
var ous = await db.OrganizationUnits.ToListAsync().ConfigureAwait(false);
|
||||
var sb = new StringBuilder();
|
||||
NewMethod(ous, null, 0, ref sb);
|
||||
var result = sb.ToString();
|
||||
Assert.Pass();
|
||||
|
||||
}
|
||||
|
||||
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>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<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="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>
|
||||
|
BIN
UserService.db
BIN
UserService.db
Binary file not shown.
@ -9,6 +9,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UserService.Test", "UserSer
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UserService.DatabaseLayer", "UserService.DatabaseLayer\UserService.DatabaseLayer.csproj", "{4505C991-7E39-416F-94E5-D906DD0D90F9}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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}.Release|Any CPU.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1,5 +1,4 @@
|
||||
|
||||
<CascadingAuthenticationState>
|
||||
<CascadingAuthenticationState>
|
||||
<Router AppAssembly="@typeof(Program).Assembly">
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
|
||||
@ -10,4 +9,4 @@
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</CascadingAuthenticationState>
|
||||
</CascadingAuthenticationState>
|
@ -1,11 +1,12 @@
|
||||
@page "/directory"
|
||||
@using UserService.DatabaseLayer.DataModels
|
||||
@using UserService.DatabaseLayer.Repository
|
||||
@inject IOrganizationUnitsRepository OuRepository
|
||||
@inherits DirectoryBase
|
||||
|
||||
<h1>TODO</h1>
|
||||
|
||||
@if (_organizationUnits == null)
|
||||
<Row>
|
||||
<Column ColumnSize="ColumnSize.Is12">
|
||||
<h1>TODO</h1>
|
||||
</Column>
|
||||
</Row>
|
||||
@if (OrganizationUnits == null)
|
||||
{
|
||||
<p>
|
||||
<em>Loading...</em>
|
||||
@ -13,17 +14,20 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
@code {
|
||||
private IReadOnlyList<OrganizationUnit> _organizationUnits;
|
||||
private OrganizationUnit _selectedOu;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_organizationUnits = (await OuRepository.GetAllAsync().ConfigureAwait(false)).Where(x=> x.Parent is null).ToList();
|
||||
}
|
||||
|
||||
<Row>
|
||||
<Column ColumnSize="ColumnSize.Is4">
|
||||
<TreeView Nodes="OrganizationUnits"
|
||||
GetChildNodes="@(item => item?.Children)"
|
||||
HasChildNodes="@(item => item?.Children?.Any() == true)"
|
||||
@bind-SelectedNode="@SelectedNode">
|
||||
<NodeContent>
|
||||
<Icon Name="IconName.Folder" />
|
||||
@context?.CommonName
|
||||
</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"
|
||||
@using UserService.DatabaseLayer.DataModels
|
||||
@using UserService.DatabaseLayer.Repository
|
||||
@using UserService.Infrastructure.DataModels
|
||||
@inherits SecurityGroupsBase
|
||||
|
||||
<h1>Table of all security groups</h1>
|
||||
|
||||
@if (SecurityGroups is null)
|
||||
@if (Members is null)
|
||||
{
|
||||
<p>
|
||||
<em>Loading...</em>
|
||||
</p>
|
||||
<p>
|
||||
<em>Loading...</em>
|
||||
</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MatTable Items="@SecurityGroups" class="mat-elevation-z5">
|
||||
<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>
|
||||
<TextEdit Placeholder="Search" Size="Size.Large" @bind-Text="@CustomFilterValue" />
|
||||
|
||||
</MatTableRow>
|
||||
</MatTable>
|
||||
<MatButton @onclick="@(e => EditSecurityGroup(new SecurityGroup()))">Create new group</MatButton>
|
||||
}
|
||||
<DataGrid
|
||||
TItem="SecurityGroup"
|
||||
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" />
|
||||
|
||||
<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>
|
||||
<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>
|
||||
}
|
@ -1,47 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Blazorise.DataGrid;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using UserService.DatabaseLayer.DataModels;
|
||||
using UserService.DatabaseLayer.Repository;
|
||||
using UserService.Infrastructure.DataModels;
|
||||
|
||||
namespace UserService.Pages
|
||||
{
|
||||
public class SecurityGroupsBase : ComponentBase
|
||||
public class SecurityGroupsBase : MembersBase<SecurityGroup>
|
||||
{
|
||||
[Inject] private ISecurityGroupsRepository? SecurityGroupsRepository { get; set; }
|
||||
[Inject] private IOrganizationUnitsRepository? OrganizationUnitsRepository { get; set; }
|
||||
|
||||
protected bool DialogIsOpen;
|
||||
protected SecurityGroup? SecurityGroupToEdit;
|
||||
|
||||
protected IReadOnlyList<SecurityGroup>? SecurityGroups;
|
||||
protected IReadOnlyList<OrganizationUnit>? OrganizationUnits;
|
||||
[Inject] private ISecurityGroupsRepository SecurityGroupsRepository { get; set; } = null!;
|
||||
[Inject] private IOrganizationUnitsRepository OrganizationUnitsRepository { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
SecurityGroups = await SecurityGroupsRepository.GetAllAsync().ConfigureAwait(false);
|
||||
Members = await SecurityGroupsRepository.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"
|
||||
@using UserService.DatabaseLayer.DataModels
|
||||
@using UserService.Infrastructure.DataModels
|
||||
@inherits UsersBase
|
||||
|
||||
<h1>List of all users</h1>
|
||||
|
||||
@if (Users == null)
|
||||
@if (Members == null)
|
||||
{
|
||||
<p>
|
||||
<em>Loading...</em>
|
||||
@ -12,55 +12,92 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<MatTable Items="@Users" class="mat-elevation-z5">
|
||||
<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>
|
||||
<TextEdit Placeholder="Search" Size="Size.Large" @bind-Text="@CustomFilterValue" />
|
||||
|
||||
<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" />
|
||||
|
||||
<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>
|
||||
<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>
|
||||
}
|
@ -1,44 +1,99 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
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.Infrastructure;
|
||||
using UserService.Infrastructure.DataModels;
|
||||
|
||||
namespace UserService.Pages
|
||||
{
|
||||
public class UsersBase : ComponentBase
|
||||
public class UsersBase : MembersBase<User>
|
||||
{
|
||||
[Inject] private IUsersRepository UsersRepository { get; set; } = null!;
|
||||
[Inject] private IOrganizationUnitsRepository OrganizationUnitsRepository { get; set; } = null!;
|
||||
|
||||
protected bool DialogIsOpen { get; set; }
|
||||
protected User? UserToEdit { get; private set; }
|
||||
|
||||
protected IReadOnlyList<User>? Users { get; private set; }
|
||||
protected IReadOnlyList<OrganizationUnit>? OrganizationUnits { get; private set; }
|
||||
[Inject] private IJSRuntime JsRuntime { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Users = await UsersRepository.GetAllAsync();
|
||||
Members = await UsersRepository.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;
|
||||
UserToEdit = user;
|
||||
if (arg is null) throw new ArgumentNullException(nameof(arg));
|
||||
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;
|
||||
await UsersRepository.UpdateAsync(UserToEdit).ConfigureAwait(false);
|
||||
DialogIsOpen = false;
|
||||
if (arg is null) throw new ArgumentNullException(nameof(arg));
|
||||
var user = arg.Item;
|
||||
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>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<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 href="css/site.css" rel="stylesheet"/>
|
||||
<script src="_content/MatBlazor/dist/matBlazor.js"></script>
|
||||
<link href="_content/MatBlazor/dist/matBlazor.css" rel="stylesheet"/>
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.0/css/all.css">
|
||||
|
||||
<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>
|
||||
<body>
|
||||
<app>
|
||||
<component type="typeof(App)" render-mode="ServerPrerendered"/>
|
||||
</app>
|
||||
<app>
|
||||
<component type="typeof(App)" render-mode="ServerPrerendered" />
|
||||
</app>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
<environment include="Staging,Production">
|
||||
An error has occurred. This application may no longer respond until reloaded.
|
||||
</environment>
|
||||
<environment include="Development">
|
||||
An unhandled exception has occurred. See browser dev tools for details.
|
||||
</environment>
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</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="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://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
|
||||
<script src="_framework/blazor.server.js"></script>
|
||||
<div id="blazor-error-ui">
|
||||
<environment include="Staging,Production">
|
||||
An error has occurred. This application may no longer respond until reloaded.
|
||||
</environment>
|
||||
<environment include="Development">
|
||||
An unhandled exception has occurred. See browser dev tools for details.
|
||||
</environment>
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
<script src="_framework/blazor.server.js"></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://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" 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="_content/Blazorise/blazorise.js"></script>
|
||||
<script src="_content/Blazorise.Bootstrap/blazorise.bootstrap.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,49 +1,38 @@
|
||||
<div class="top-row pl-4 navbar navbar-dark">
|
||||
<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>
|
||||
<Sidebar Data="@_sidebarInfo" />
|
||||
|
||||
@code {
|
||||
private bool _collapseNavMenu = true;
|
||||
private SidebarInfo _sidebarInfo;
|
||||
|
||||
private string NavMenuCssClass => _collapseNavMenu ? "collapse" : null;
|
||||
|
||||
private void ToggleNavMenu()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_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.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@ -26,12 +29,19 @@ namespace UserService
|
||||
services.AddSingleton<IUsersRepository, UsersRepository>();
|
||||
services.AddSingleton<ISecurityGroupsRepository, SecurityGroupsRepository>();
|
||||
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.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
@ -48,6 +58,10 @@ namespace UserService
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.ApplicationServices
|
||||
.UseBootstrapProviders()
|
||||
.UseFontAwesomeIcons();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapBlazorHub();
|
||||
@ -55,4 +69,4 @@ namespace UserService
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,14 +3,28 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MatBlazor" Version="2.6.2" />
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<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>
|
||||
|
||||
</Project>
|
||||
|
@ -7,4 +7,7 @@
|
||||
@using Microsoft.JSInterop
|
||||
@using UserService
|
||||
@using UserService.Shared
|
||||
@using MatBlazor
|
||||
@using Blazorise
|
||||
@using Blazorise.Sidebar
|
||||
@using Blazorise.TreeView
|
||||
@using Blazorise.DataGrid
|
||||
|
Loading…
x
Reference in New Issue
Block a user