Created AdminContext handling

This commit is contained in:
2024-09-30 19:01:39 +02:00
parent 672f0fd2c3
commit 66ddc22012
33 changed files with 582 additions and 7 deletions

View File

@@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Web", "src\HopFram
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontendTest", "test\FrontendTest\FrontendTest.csproj", "{8F983A37-63CF-48D5-988D-58B78EF8AECD}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontendTest", "test\FrontendTest\FrontendTest.csproj", "{8F983A37-63CF-48D5-988D-58B78EF8AECD}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Web.Admin", "src\HopFrame.Web.Admin\HopFrame.Web.Admin.csproj", "{02D9F10A-664A-4EF7-BF19-310C26FF4DEB}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -42,6 +44,10 @@ Global
{8F983A37-63CF-48D5-988D-58B78EF8AECD}.Debug|Any CPU.Build.0 = Debug|Any CPU {8F983A37-63CF-48D5-988D-58B78EF8AECD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F983A37-63CF-48D5-988D-58B78EF8AECD}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F983A37-63CF-48D5-988D-58B78EF8AECD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F983A37-63CF-48D5-988D-58B78EF8AECD}.Release|Any CPU.Build.0 = Release|Any CPU {8F983A37-63CF-48D5-988D-58B78EF8AECD}.Release|Any CPU.Build.0 = Release|Any CPU
{02D9F10A-664A-4EF7-BF19-310C26FF4DEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{02D9F10A-664A-4EF7-BF19-310C26FF4DEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{02D9F10A-664A-4EF7-BF19-310C26FF4DEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{02D9F10A-664A-4EF7-BF19-310C26FF4DEB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
EndGlobalSection EndGlobalSection

View File

@@ -22,4 +22,8 @@
<None Include="README.md" Pack="true" PackagePath="\"/> <None Include="README.md" Pack="true" PackagePath="\"/>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HopFrame.Web.Admin\HopFrame.Web.Admin.csproj" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,22 +1,27 @@
using System.ComponentModel; using System.ComponentModel;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using HopFrame.Web.Admin.Attributes;
using HopFrame.Web.Admin.Attributes.Members;
namespace HopFrame.Database.Models; namespace HopFrame.Database.Models;
[AdminName("Groups")]
[AdminDescription("On this page you can view, create, edit and delete permission groups.")]
public class PermissionGroup : IPermissionOwner { public class PermissionGroup : IPermissionOwner {
[Key, Required, MaxLength(50)] [Key, Required, MaxLength(50)]
public string Name { get; init; } public string Name { get; init; }
[Required, DefaultValue(false)] [Required, DefaultValue(false), AdminUnsortable]
public bool IsDefaultGroup { get; set; } public bool IsDefaultGroup { get; set; }
[MaxLength(500)] [MaxLength(500)]
public string Description { get; set; } public string Description { get; set; }
[Required] [Required, AdminUneditable]
public DateTime CreatedAt { get; set; } public DateTime CreatedAt { get; set; }
[AdminIgnore(onlyForListing: true)]
public virtual IList<Permission> Permissions { get; set; } public virtual IList<Permission> Permissions { get; set; }
} }

View File

@@ -1,8 +1,11 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using HopFrame.Web.Admin.Attributes;
using HopFrame.Web.Admin.Attributes.Members;
namespace HopFrame.Database.Models; namespace HopFrame.Database.Models;
[AdminDescription("On this page you can manage all user accounts.")]
public class User : IPermissionOwner { public class User : IPermissionOwner {
[Key, Required, MinLength(36), MaxLength(36)] [Key, Required, MinLength(36), MaxLength(36)]
@@ -14,15 +17,16 @@ public class User : IPermissionOwner {
[Required, MaxLength(50), EmailAddress] [Required, MaxLength(50), EmailAddress]
public string Email { get; set; } public string Email { get; set; }
[Required, MinLength(8), MaxLength(255), JsonIgnore] [Required, MinLength(8), MaxLength(255), JsonIgnore, AdminIgnore(onlyForListing: true), AdminHideValue]
public string Password { get; set; } public string Password { get; set; }
[Required] [Required, AdminUneditable]
public DateTime CreatedAt { get; set; } public DateTime CreatedAt { get; set; }
[AdminIgnore(onlyForListing: true)]
public virtual IList<Permission> Permissions { get; set; } public virtual IList<Permission> Permissions { get; set; }
[JsonIgnore] [JsonIgnore, AdminIgnore]
public virtual IList<Token> Tokens { get; set; } public virtual IList<Token> Tokens { get; set; }
} }

View File

@@ -0,0 +1,9 @@
using HopFrame.Web.Admin.Generators;
namespace HopFrame.Web.Admin;
public abstract class AdminPagesContext {
public abstract void OnModelCreating(IAdminContextGenerator generator);
}

View File

@@ -0,0 +1,6 @@
namespace HopFrame.Web.Admin.Attributes;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public class AdminDescriptionAttribute(string description) : Attribute {
public string Description { get; set; } = description;
}

View File

@@ -0,0 +1,6 @@
namespace HopFrame.Web.Admin.Attributes;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public class AdminNameAttribute(string name) : Attribute {
public string Name { get; set; } = name;
}

View File

@@ -0,0 +1,8 @@
namespace HopFrame.Web.Admin.Attributes.Classes;
[AttributeUsage(AttributeTargets.Class)]
public class AdminButtonConfigAttribute(bool showCreateButton = true, bool showDeleteButton = true, bool showUpdateButton = true) : Attribute {
public bool ShowCreateButton { get; set; } = showCreateButton;
public bool ShowDeleteButton { get; set; } = showDeleteButton;
public bool ShowUpdateButton { get; set; } = showUpdateButton;
}

View File

@@ -0,0 +1,8 @@
using HopFrame.Web.Admin.Models;
namespace HopFrame.Web.Admin.Attributes.Classes;
[AttributeUsage(AttributeTargets.Class)]
public class AdminPermissionsAttribute(AdminPagePermissions permissions) : Attribute {
public AdminPagePermissions Permissions { get; set; } = permissions;
}

View File

@@ -0,0 +1,4 @@
namespace HopFrame.Web.Admin.Attributes.Members;
[AttributeUsage(AttributeTargets.Property)]
public class AdminBoldAttribute : Attribute;

View File

@@ -0,0 +1,4 @@
namespace HopFrame.Web.Admin.Attributes.Members;
[AttributeUsage(AttributeTargets.Property)]
public class AdminHideValueAttribute : Attribute;

View File

@@ -0,0 +1,6 @@
namespace HopFrame.Web.Admin.Attributes.Members;
[AttributeUsage(AttributeTargets.Property)]
public class AdminIgnoreAttribute(bool onlyForListing = false) : Attribute {
public bool OnlyForListing { get; set; } = onlyForListing;
}

View File

@@ -0,0 +1,4 @@
namespace HopFrame.Web.Admin.Attributes.Members;
[AttributeUsage(AttributeTargets.Property)]
public class AdminUneditableAttribute : Attribute;

View File

@@ -0,0 +1,4 @@
namespace HopFrame.Web.Admin.Attributes.Members;
[AttributeUsage(AttributeTargets.Property)]
public class AdminUnsortableAttribute : Attribute;

View File

@@ -0,0 +1,7 @@
namespace HopFrame.Web.Admin.Generators;
public interface IAdminContextGenerator {
IAdminPageGenerator<TModel> Page<TModel>();
}

View File

@@ -0,0 +1,26 @@
using System.ComponentModel;
using System.Linq.Expressions;
namespace HopFrame.Web.Admin.Generators;
public interface IAdminPageGenerator<TModel> {
IAdminPageGenerator<TModel> Title(string title);
IAdminPageGenerator<TModel> Description(string description);
IAdminPageGenerator<TModel> ViewPermission(string permission);
IAdminPageGenerator<TModel> CreatePermission(string permission);
IAdminPageGenerator<TModel> UpdatePermission(string permission);
IAdminPageGenerator<TModel> DeletePermission(string permission);
IAdminPageGenerator<TModel> ShowCreateButton(bool show);
IAdminPageGenerator<TModel> ShowDeleteButton(bool show);
IAdminPageGenerator<TModel> ShowUpdateButton(bool show);
IAdminPageGenerator<TModel> DefaultSort<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression, ListSortDirection direction);
IAdminPageGenerator<TModel> ConfigureRepository<TRepository>() where TRepository : IModelRepository<TModel>;
IAdminPropertyGenerator Property<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression);
}

View File

@@ -0,0 +1,14 @@
namespace HopFrame.Web.Admin.Generators;
public interface IAdminPropertyGenerator {
IAdminPropertyGenerator Sortable(bool sortable);
IAdminPropertyGenerator Editable(bool editable);
IAdminPropertyGenerator DisplayValueWhileEditing(bool display);
IAdminPropertyGenerator DisplayInListing(bool display = true);
IAdminPropertyGenerator Bold(bool isBold = true);
IAdminPropertyGenerator DisplayName(string displayName);
IAdminPropertyGenerator Description(string description);
}

View File

@@ -0,0 +1,7 @@
namespace HopFrame.Web.Admin.Generators;
public interface IGenerator<out TGeneratedType> {
TGeneratedType Compile();
}

View File

@@ -0,0 +1,91 @@
using System.Reflection;
using HopFrame.Web.Admin.Attributes;
using HopFrame.Web.Admin.Attributes.Classes;
using HopFrame.Web.Admin.Models;
namespace HopFrame.Web.Admin.Generators.Implementation;
internal class AdminContextGenerator : IAdminContextGenerator {
private readonly IDictionary<Type, object> _adminPages = new Dictionary<Type, object>();
public IAdminPageGenerator<TModel> Page<TModel>() {
if (_adminPages.TryGetValue(typeof(TModel), out var pageGenerator))
return pageGenerator as IAdminPageGenerator<TModel>;
var generator = Activator.CreateInstance(typeof(IAdminPageGenerator<TModel>)) as IAdminPageGenerator<TModel>;
ApplyConfigurationFromAttributes(generator, typeof(TModel).GetCustomAttributes(false));
_adminPages.Add(typeof(TModel), generator);
return generator;
}
public AdminPage<TModel> CompilePage<TModel>() {
var generator = _adminPages[typeof(TModel)];
if (generator is null) return null;
return (generator as AdminPageGenerator<TModel>)?.Compile();
}
public TContext CompileContext<TContext>() where TContext : AdminPagesContext {
var type = typeof(TContext);
var compileMethod = typeof(AdminContextGenerator).GetMethod(nameof(CompilePage));
var properties = type.GetProperties();
var context = Activator.CreateInstance<TContext>();
foreach (var property in properties) {
var propertyType = property.PropertyType.GenericTypeArguments[0];
var pageGeneratorType = typeof(AdminPageGenerator<>).MakeGenericType(propertyType);
var generatorInstance = Activator.CreateInstance(pageGeneratorType, [propertyType.Name]);
var populatorMethod = typeof(AdminContextGenerator)
.GetMethod(nameof(ApplyConfigurationFromAttributes))?
.MakeGenericMethod(propertyType);
populatorMethod?.Invoke(this, [generatorInstance, propertyType.GetCustomAttributes()]);
_adminPages.Add(propertyType, generatorInstance);
}
context.OnModelCreating(this);
foreach (var property in properties) {
var modelType = property.PropertyType.GenericTypeArguments[0];
var method = compileMethod?.MakeGenericMethod(modelType);
property.SetValue(context, method?.Invoke(this, []));
}
return context;
}
public void ApplyConfigurationFromAttributes<TModel>(IAdminPageGenerator<TModel> generator, object[] attributes) {
if (attributes.Any(a => a is AdminNameAttribute)) {
var attribute = attributes.Single(a => a is AdminNameAttribute) as AdminNameAttribute;
generator.Title(attribute?.Name);
}
if (attributes.Any(a => a is AdminDescriptionAttribute)) {
var attribute = attributes.Single(a => a is AdminDescriptionAttribute) as AdminDescriptionAttribute;
generator.Description(attribute?.Description);
}
if (attributes.Any(a => a is AdminPermissionsAttribute)) {
var attribute = attributes.Single(a => a is AdminPermissionsAttribute) as AdminPermissionsAttribute;
generator.CreatePermission(attribute?.Permissions.Create);
generator.UpdatePermission(attribute?.Permissions.Update);
generator.ViewPermission(attribute?.Permissions.View);
generator.DeletePermission(attribute?.Permissions.Delete);
}
if (attributes.Any(a => a is AdminButtonConfigAttribute)) {
var attribute = attributes.Single(a => a is AdminButtonConfigAttribute) as AdminButtonConfigAttribute;
generator.ShowCreateButton(attribute?.ShowCreateButton == true);
generator.ShowUpdateButton(attribute?.ShowUpdateButton == true);
generator.ShowDeleteButton(attribute?.ShowDeleteButton == true);
}
}
}

View File

@@ -0,0 +1,180 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
using System.Reflection;
using HopFrame.Web.Admin.Attributes;
using HopFrame.Web.Admin.Attributes.Members;
using HopFrame.Web.Admin.Models;
namespace HopFrame.Web.Admin.Generators.Implementation;
internal sealed class AdminPageGenerator<TModel> : IAdminPageGenerator<TModel>, IGenerator<AdminPage<TModel>> {
private readonly AdminPage<TModel> _page;
private readonly IDictionary<string, AdminPropertyGenerator> _propertyGenerators;
public AdminPageGenerator() {
_page = new AdminPage<TModel> {
Permissions = new AdminPagePermissions()
};
_propertyGenerators = new Dictionary<string, AdminPropertyGenerator>();
var type = typeof(TModel);
var properties = type.GetProperties();
foreach (var property in properties) {
var attributes = property.GetCustomAttributes(false);
var ignoreProperty = attributes
.SingleOrDefault(a => a is AdminIgnoreAttribute) as AdminIgnoreAttribute;
if (ignoreProperty?.OnlyForListing == false) continue;
var generator = Activator.CreateInstance(typeof(AdminPropertyGenerator), [property.Name, property.PropertyType]) as AdminPropertyGenerator;
ApplyConfigurationFromAttributes(generator, attributes, property);
_propertyGenerators.Add(property.Name, generator);
}
}
public AdminPageGenerator(string title) : this() {
Title(title);
}
public IAdminPageGenerator<TModel> Title(string title) {
_page.Title = title;
return this;
}
public IAdminPageGenerator<TModel> Description(string description) {
_page.Description = description;
return this;
}
public IAdminPageGenerator<TModel> ViewPermission(string permission) {
_page.Permissions.View = permission;
return this;
}
public IAdminPageGenerator<TModel> CreatePermission(string permission) {
_page.Permissions.Create = permission;
return this;
}
public IAdminPageGenerator<TModel> UpdatePermission(string permission) {
_page.Permissions.Update = permission;
return this;
}
public IAdminPageGenerator<TModel> DeletePermission(string permission) {
_page.Permissions.Delete = permission;
return this;
}
public IAdminPageGenerator<TModel> ShowCreateButton(bool show) {
_page.ShowCreateButton = show;
return this;
}
public IAdminPageGenerator<TModel> ShowDeleteButton(bool show) {
_page.ShowDeleteButton = show;
return this;
}
public IAdminPageGenerator<TModel> ShowUpdateButton(bool show) {
_page.ShowUpdateButton = show;
return this;
}
public IAdminPageGenerator<TModel> DefaultSort<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression, ListSortDirection direction) {
var property = GetPropertyInfo(propertyExpression);
_page.DefaultSortPropertyName = property.Name;
_page.DefaultSortDirection = direction;
return this;
}
public IAdminPageGenerator<TModel> ConfigureRepository<TRepository>() where TRepository : IModelRepository<TModel> {
_page.RepositoryProvider = typeof(TRepository);
return this;
}
public IAdminPropertyGenerator Property<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression) {
var property = GetPropertyInfo(propertyExpression);
if (_propertyGenerators.TryGetValue(property.Name, out var propertyGenerator))
return propertyGenerator;
var generator = Activator.CreateInstance(typeof(AdminPropertyGenerator), new { property.Name, property.PropertyType }) as AdminPropertyGenerator;
ApplyConfigurationFromAttributes(generator, property.GetCustomAttributes(false), property);
_propertyGenerators.Add(property.Name, generator);
return generator;
}
public AdminPage<TModel> Compile() {
var properties = new List<AdminPageProperty>();
foreach (var generator in _propertyGenerators.Values){
properties.Add(generator.Compile());
}
_page.Properties = properties;
return _page;
}
private void ApplyConfigurationFromAttributes(AdminPropertyGenerator generator, object[] attributes, PropertyInfo property) {
if (attributes.Any(a => a is KeyAttribute)) {
_page.DefaultSortPropertyName = property.Name;
generator.Bold();
generator.Editable(false);
}
if (attributes.Any(a => a is AdminUnsortableAttribute))
generator.Sortable(false);
if (attributes.Any(a => a is AdminUneditableAttribute))
generator.Editable(false);
if (attributes.Any(a => a is AdminBoldAttribute))
generator.Bold();
if (attributes.Any(a => a is AdminIgnoreAttribute))
generator.DisplayInListing(false);
if (attributes.Any(a => a is AdminHideValueAttribute))
generator.DisplayValueWhileEditing(false);
if (attributes.Any(a => a is AdminNameAttribute)) {
var attribute = attributes.Single(a => a is AdminNameAttribute) as AdminNameAttribute;
generator.DisplayName(attribute?.Name);
}
if (attributes.Any(a => a is AdminDescriptionAttribute)) {
var attribute = attributes.Single(a => a is AdminDescriptionAttribute) as AdminDescriptionAttribute;
generator.Description(attribute?.Description);
}
}
private static PropertyInfo GetPropertyInfo<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda) {
if (propertyLambda.Body is not MemberExpression member) {
throw new ArgumentException($"Expression '{propertyLambda}' refers to a method, not a property.");
}
if (member.Member is not PropertyInfo propInfo) {
throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property.");
}
Type type = typeof(TSource);
if (propInfo.ReflectedType != null && type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType)) {
throw new ArgumentException($"Expression '{propertyLambda}' refers to a property that is not from type {type}.");
}
if (propInfo.Name is null)
throw new ArgumentException($"Expression '{propertyLambda}' refers a not existing property.");
return propInfo;
}
}

View File

@@ -0,0 +1,52 @@
using HopFrame.Web.Admin.Models;
namespace HopFrame.Web.Admin.Generators.Implementation;
internal sealed class AdminPropertyGenerator(string name, Type type) : IAdminPropertyGenerator, IGenerator<AdminPageProperty> {
private readonly AdminPageProperty _property = new() {
Name = name,
Type = type
};
public IAdminPropertyGenerator Sortable(bool sortable) {
_property.Sortable = sortable;
return this;
}
public IAdminPropertyGenerator Editable(bool editable) {
_property.Editable = editable;
return this;
}
public IAdminPropertyGenerator DisplayValueWhileEditing(bool display) {
_property.EditDisplayValue = display;
return this;
}
public IAdminPropertyGenerator DisplayInListing(bool display = true) {
_property.DisplayInListing = display;
return this;
}
public IAdminPropertyGenerator Bold(bool isBold = true) {
_property.Bold = isBold;
return this;
}
public IAdminPropertyGenerator DisplayName(string displayName) {
_property.DisplayName = displayName;
return this;
}
public IAdminPropertyGenerator Description(string description) {
_property.Description = description;
return this;
}
public AdminPageProperty Compile() {
_property.DisplayName ??= _property.Name;
return _property;
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
namespace HopFrame.Web.Admin;
public interface IModelRepository<TModel> {
Task<IEnumerable<TModel>> ReadAll();
Task<TModel> Create(TModel model);
Task<TModel> Update(TModel model);
Task Delete(TModel model);
}

View File

@@ -0,0 +1,22 @@
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace HopFrame.Web.Admin.Models;
public class AdminPage<TModel> : IAdminPageEntry {
public string Title { get; set; }
public string Description { get; set; }
public AdminPagePermissions Permissions { get; set; }
public IList<AdminPageProperty> Properties { get; set; }
[JsonIgnore]
public Type RepositoryProvider { get; set; }
public string DefaultSortPropertyName { get; set; }
public ListSortDirection DefaultSortDirection { get; set; }
public bool ShowCreateButton { get; set; } = true;
public bool ShowDeleteButton { get; set; } = true;
public bool ShowUpdateButton { get; set; } = true;
}
public interface IAdminPageEntry;

View File

@@ -0,0 +1,8 @@
namespace HopFrame.Web.Admin.Models;
public class AdminPagePermissions {
public string View { get; set; }
public string Create { get; set; }
public string Update { get; set; }
public string Delete { get; set; }
}

View File

@@ -0,0 +1,17 @@
using System.Text.Json.Serialization;
namespace HopFrame.Web.Admin.Models;
public class AdminPageProperty {
public string Name { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public bool DisplayInListing { get; set; } = true;
public bool Sortable { get; set; } = true;
public bool Editable { get; set; } = true;
public bool EditDisplayValue { get; set; } = true;
public bool Bold { get; set; }
[JsonIgnore]
public Type Type { get; set; }
}

View File

@@ -0,0 +1,17 @@
using HopFrame.Web.Admin.Generators.Implementation;
using Microsoft.Extensions.DependencyInjection;
namespace HopFrame.Web.Admin;
public static class ServiceCollectionExtensions {
public static IServiceCollection AddAdminContext<TContext>(this IServiceCollection services) where TContext : AdminPagesContext {
services.AddSingleton(_ => {
var generator = new AdminContextGenerator();
return generator.CompileContext<TContext>();
});
return services;
}
}

View File

@@ -20,6 +20,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\HopFrame.Database\HopFrame.Database.csproj" /> <ProjectReference Include="..\HopFrame.Database\HopFrame.Database.csproj" />
<ProjectReference Include="..\HopFrame.Security\HopFrame.Security.csproj" /> <ProjectReference Include="..\HopFrame.Security\HopFrame.Security.csproj" />
<ProjectReference Include="..\HopFrame.Web.Admin\HopFrame.Web.Admin.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>disable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>

View File

@@ -1,6 +1,7 @@
using FrontendTest; using FrontendTest;
using FrontendTest.Components; using FrontendTest.Components;
using HopFrame.Web; using HopFrame.Web;
using HopFrame.Web.Admin;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);

View File

@@ -0,0 +1,26 @@
using System.ComponentModel;
using HopFrame.Database.Models;
using HopFrame.Web.Admin;
using HopFrame.Web.Admin.Generators;
using HopFrame.Web.Admin.Models;
namespace RestApiTest;
public class AdminContext : AdminPagesContext {
public AdminPage<User> Users { get; set; }
public AdminPage<PermissionGroup> Groups { get; set; }
public override void OnModelCreating(IAdminContextGenerator generator) {
/*generator.Page<User>()
.Title("Users")
.Description("On this page you can manage all user accounts.")
.UpdatePermission("update")
.ViewPermission("view")
.DeletePermission("delete")
.CreatePermission("create")
.DefaultSort(u => u.Id, ListSortDirection.Descending);*/
}
}

View File

@@ -10,7 +10,7 @@ namespace RestApiTest.Controllers;
[ApiController] [ApiController]
[Route("test")] [Route("test")]
public class TestController(ITokenContext userContext, DatabaseContext context) : ControllerBase { public class TestController(ITokenContext userContext, DatabaseContext context, AdminContext adminContext) : ControllerBase {
[HttpGet("permissions"), Authorized] [HttpGet("permissions"), Authorized]
public ActionResult<IList<Permission>> Permissions() { public ActionResult<IList<Permission>> Permissions() {
@@ -51,4 +51,9 @@ public class TestController(ITokenContext userContext, DatabaseContext context)
return LogicResult<IList<Address>>.Ok(await context.Addresses.Include(e => e.Employee).ToListAsync()); return LogicResult<IList<Address>>.Ok(await context.Addresses.Include(e => e.Employee).ToListAsync());
} }
[HttpGet("adminContext")]
public ActionResult<AdminContext> GetAdminContext() {
return LogicResult<AdminContext>.Ok(adminContext);
}
} }

View File

@@ -1,5 +1,6 @@
using RestApiTest; using RestApiTest;
using HopFrame.Api.Extensions; using HopFrame.Api.Extensions;
using HopFrame.Web.Admin;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@@ -13,6 +14,7 @@ builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<DatabaseContext>(); builder.Services.AddDbContext<DatabaseContext>();
builder.Services.AddAdminContext<AdminContext>();
builder.Services.AddSwaggerGen(c => { builder.Services.AddSwaggerGen(c => {
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {