diff --git a/HopFrame.sln.DotSettings.user b/HopFrame.sln.DotSettings.user index f66ed72..baebe71 100644 --- a/HopFrame.sln.DotSettings.user +++ b/HopFrame.sln.DotSettings.user @@ -1,4 +1,5 @@  + ForceIncluded <AssemblyExplorer> <Assembly Path="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.16\ref\net7.0\System.ComponentModel.Annotations.dll" /> <Assembly Path="C:\Users\Remote\.nuget\packages\blazorstrap\5.2.100.61524\lib\net7.0\BlazorStrap.dll" /> diff --git a/src/HopFrame.Database/Models/PermissionGroup.cs b/src/HopFrame.Database/Models/PermissionGroup.cs index 7a70ebd..aa0c92c 100644 --- a/src/HopFrame.Database/Models/PermissionGroup.cs +++ b/src/HopFrame.Database/Models/PermissionGroup.cs @@ -17,6 +17,6 @@ public class PermissionGroup : IPermissionOwner { [Required] public DateTime CreatedAt { get; set; } - public virtual IList Permissions { get; set; } + public virtual List Permissions { get; set; } } \ No newline at end of file diff --git a/src/HopFrame.Database/Models/User.cs b/src/HopFrame.Database/Models/User.cs index 971d899..2b73010 100644 --- a/src/HopFrame.Database/Models/User.cs +++ b/src/HopFrame.Database/Models/User.cs @@ -20,9 +20,9 @@ public class User : IPermissionOwner { [Required] public DateTime CreatedAt { get; set; } - public virtual IList Permissions { get; set; } + public virtual List Permissions { get; set; } [JsonIgnore] - public virtual IList Tokens { get; set; } + public virtual List Tokens { get; set; } } \ No newline at end of file diff --git a/src/HopFrame.Web.Admin/Generators/IAdminPropertyGenerator.cs b/src/HopFrame.Web.Admin/Generators/IAdminPropertyGenerator.cs index 745dbb5..720b103 100644 --- a/src/HopFrame.Web.Admin/Generators/IAdminPropertyGenerator.cs +++ b/src/HopFrame.Web.Admin/Generators/IAdminPropertyGenerator.cs @@ -17,6 +17,8 @@ public interface IAdminPropertyGenerator { IAdminPropertyGenerator Prefix(string prefix); IAdminPropertyGenerator Validator(Func validator); IAdminPropertyGenerator IsSelector(); + IAdminPropertyGenerator Parser(Func parser); + IAdminPropertyGenerator ParserForListType(Func parser); IAdminPropertyGenerator DisplayProperty(Expression> propertyExpression); IAdminPropertyGenerator DisplayPropertyForListType(Expression> propertyExpression); diff --git a/src/HopFrame.Web.Admin/Generators/Implementation/AdminPropertyGenerator.cs b/src/HopFrame.Web.Admin/Generators/Implementation/AdminPropertyGenerator.cs index b626463..3cb2368 100644 --- a/src/HopFrame.Web.Admin/Generators/Implementation/AdminPropertyGenerator.cs +++ b/src/HopFrame.Web.Admin/Generators/Implementation/AdminPropertyGenerator.cs @@ -76,6 +76,16 @@ internal sealed class AdminPropertyGenerator(string name, Type type) return this; } + public IAdminPropertyGenerator Parser(Func parser) { + _property.Parser = (o, s) => parser.Invoke((TModel)o, s); + return this; + } + + public IAdminPropertyGenerator ParserForListType(Func parser) { + _property.Parser = (o, s) => parser.Invoke((TModel)o, s); + return this; + } + public IAdminPropertyGenerator DisplayProperty(Expression> propertyExpression) { var property = AdminPageGenerator.GetPropertyInfo(propertyExpression); _property.DisplayPropertyName = property.Name; diff --git a/src/HopFrame.Web.Admin/Models/AdminPageProperty.cs b/src/HopFrame.Web.Admin/Models/AdminPageProperty.cs index f1b1ddd..95eadc4 100644 --- a/src/HopFrame.Web.Admin/Models/AdminPageProperty.cs +++ b/src/HopFrame.Web.Admin/Models/AdminPageProperty.cs @@ -23,6 +23,7 @@ public sealed class AdminPageProperty { public Type SelectorType { get; set; } public Func Validator { get; set; } + public Func Parser { get; set; } public object GetValue(object entry) { return entry.GetType().GetProperty(Name)?.GetValue(entry); diff --git a/src/HopFrame.Web/Components/Administration/AdminPageModal.razor b/src/HopFrame.Web/Components/Administration/AdminPageModal.razor index 0141634..5c05d68 100644 --- a/src/HopFrame.Web/Components/Administration/AdminPageModal.razor +++ b/src/HopFrame.Web/Components/Administration/AdminPageModal.razor @@ -5,6 +5,9 @@ @using BlazorStrap.Shared.Components.Modal @using static Microsoft.AspNetCore.Components.Web.RenderMode @using BlazorStrap.V5 +@using CurrieTechnologies.Razor.SweetAlert2 +@using HopFrame.Database.Repositories +@using HopFrame.Security.Claims @using HopFrame.Web.Admin @using HopFrame.Web.Admin.Models @using HopFrame.Web.Admin.Providers @@ -22,7 +25,7 @@ @foreach (var prop in GetEditableProperties()) { - @if (!_isEdit && !prop.Editable) continue; + @if (!_isEdit && prop.Generated) continue;
@if (IsListType(prop)) { @@ -42,10 +45,12 @@ -
+
@if (prop.SelectorType is null) { - - Add +
+ + Add +
} else { @* TODO: implement selector @@ -69,6 +74,12 @@
} + else if (prop.Prefix is not null && !_isEdit) { + + @prop.Prefix + + + } else { @prop.DisplayName @@ -86,6 +97,9 @@ @inject IServiceProvider Provider @inject IAdminPagesProvider PageProvider +@inject SweetAlertService Alerts +@inject IPermissionRepository Permissions +@inject ITokenContext Auth @code { [Parameter] @@ -129,15 +143,16 @@ .ToList(); } - private bool IsDisabled(AdminPageProperty prop) => !prop.Editable; + private bool IsDisabled(AdminPageProperty prop) => (_isEdit && !prop.Editable) || prop.Generated; private bool IsRequired(AdminPageProperty prop) => !_isEdit ? prop.Required : prop.Required && prop.EditDisplayValue; private bool IsSwitch(AdminPageProperty prop) => prop.Type == typeof(bool); private bool IsListType(AdminPageProperty prop) { if (!prop.Type.IsGenericType) return false; var generic = prop.Type.GenericTypeArguments[0]; - var listType = typeof(IList<>).MakeGenericType(generic); - return prop.Type.IsAssignableFrom(listType); + var gListType = typeof(IList<>).MakeGenericType(generic); + var iListType = typeof(List<>).MakeGenericType(generic); + return prop.Type.IsAssignableFrom(gListType) || prop.Type.IsAssignableFrom(iListType); } private IList GetListPropertyValues(AdminPageProperty prop) { @@ -178,13 +193,6 @@ } } - /*if (type.GetProperties().Any(p => p.GetCustomAttributes(false).Any(a => a is ListingPropertyAttribute))) { - var prop = type.GetProperties() - .SingleOrDefault(p => p.GetCustomAttributes(false).Any(a => a is ListingPropertyAttribute)); - - return MapPropertyValue(prop?.GetValue(value), property); - }*/ - if (!string.IsNullOrEmpty(property.DisplayPropertyName) && !isSubProperty) { var prop = type.GetProperties() .SingleOrDefault(p => p.Name == property.DisplayPropertyName); @@ -213,25 +221,76 @@ if (value.Key.Validator is null) continue; if (value.Key.Validator?.Invoke(value.Value) == true) continue; Console.WriteLine("INVALID"); + //TODO: implement validation } } private void DeleteListItem(AdminPageProperty prop, int index) { - Console.WriteLine(index); var list = prop.GetValue(_entry); list.RemoveAt(index); } + private void AddListItem(AdminPageProperty prop) { + if (!_inputValues.TryGetValue(prop, out var input)) { + Alerts.FireAsync(new SweetAlertOptions { + Title = "Error!", + Text = "Please enter a value!", + Icon = SweetAlertIcon.Error + }); + return; + } + + var list = prop.GetValue(_entry); + var value = prop.Parser?.Invoke(_entry, input) ?? input; + list?.Add(value); + } + private async void Save() { + if (_isEdit && _currentPage.Permissions.Update is not null) { + if (!await Permissions.HasPermission(Auth.User, _currentPage.Permissions.Update)) { + await Alerts.FireAsync(new SweetAlertOptions { + Title = "Unauthorized!", + Text = "You don't have the required permissions to edit an entry!", + Icon = SweetAlertIcon.Error + }); + return; + } + }else if (_currentPage.Permissions.Create is not null) { + if (!await Permissions.HasPermission(Auth.User, _currentPage.Permissions.Create)) { + await Alerts.FireAsync(new SweetAlertOptions { + Title = "Unauthorized!", + Text = "You don't have the required permissions to add an entry!", + Icon = SweetAlertIcon.Error + }); + return; + } + } + foreach (var value in _values) { - value.Key.SetValue(_entry, value.Value); + if (IsListType(value.Key)) continue; + value.Key.SetValue(_entry, value.Key.Parser?.Invoke(_entry, (string)value.Value) ?? value.Value); } if (!_isEdit) { await _repository.CreateO(_entry); + + await Alerts.FireAsync(new SweetAlertOptions { + Title = "New entry added!", + Icon = SweetAlertIcon.Success, + ShowConfirmButton = false, + Timer = 1500 + }); } else { await _repository.UpdateO(_entry); + + await Alerts.FireAsync(new SweetAlertOptions { + Title = "Entry updated!", + Icon = SweetAlertIcon.Success, + ShowConfirmButton = false, + Timer = 1500 + + }); } await ReloadDelegate.Invoke(); diff --git a/src/HopFrame.Web/HopAdminContext.cs b/src/HopFrame.Web/HopAdminContext.cs index 6da2927..84a87a5 100644 --- a/src/HopFrame.Web/HopAdminContext.cs +++ b/src/HopFrame.Web/HopAdminContext.cs @@ -30,8 +30,18 @@ public class HopAdminContext : AdminPagesContext { generator.Page().Property(u => u.Permissions) .DisplayInListing(false) - .IsSelector() - .DisplayPropertyForListType(p => p.PermissionName); + .DisplayPropertyForListType(p => p.PermissionName) + .ParserForListType((user, perm) => new Permission { + GrantedAt = DateTime.Now, + PermissionName = perm, + User = user + }); + + generator.Page().Property(u => u.CreatedAt) + .Generated(); + + generator.Page().Property(u => u.Id) + .Generated(); generator.Page().Property(u => u.Tokens) .Ignore(); @@ -49,13 +59,19 @@ public class HopAdminContext : AdminPagesContext { .Prefix("group."); generator.Page().Property(g => g.IsDefaultGroup) + .DisplayName("Default Group") .Sortable(false); generator.Page().Property(g => g.CreatedAt) - .Editable(false); + .Generated(); generator.Page().Property(g => g.Permissions) .DisplayInListing(false) - .DisplayPropertyForListType(p => p.PermissionName); + .DisplayPropertyForListType(p => p.PermissionName) + .ParserForListType((group, perm) => new Permission { + GrantedAt = DateTime.Now, + PermissionName = perm, + Group = group + }); } } \ No newline at end of file diff --git a/src/HopFrame.Web/Pages/Administration/AdminPageList.razor b/src/HopFrame.Web/Pages/Administration/AdminPageList.razor index 8932a56..947f961 100644 --- a/src/HopFrame.Web/Pages/Administration/AdminPageList.razor +++ b/src/HopFrame.Web/Pages/Administration/AdminPageList.razor @@ -130,9 +130,9 @@ _currentSortProperty = _pageData.DefaultSortPropertyName; _currentSortDirection = _pageData.DefaultSortDirection; - _modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository; - if (_modelRepository is null) + if (_pageData.RepositoryProvider is null) throw new ArgumentException($"AdminPage '{_pageData.Title}' does not specify a model repository!'"); + _modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository; _hasEditPermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Update); _hasDeletePermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Delete);