diff --git a/BLAZAM.Tests/BLAZAM.Tests.csproj b/BLAZAM.Tests/BLAZAM.Tests.csproj index 08426028..86d716a5 100644 --- a/BLAZAM.Tests/BLAZAM.Tests.csproj +++ b/BLAZAM.Tests/BLAZAM.Tests.csproj @@ -10,8 +10,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/BLAZAM/BLAZAM.csproj b/BLAZAM/BLAZAM.csproj index 2bcfbe13..9c7647fa 100644 --- a/BLAZAM/BLAZAM.csproj +++ b/BLAZAM/BLAZAM.csproj @@ -1,12 +1,12 @@ - + net6.0 enable enable false - 0.9.4 - 2024.07.23.0006 + 0.9.5 + 2024.07.27.2017 false BLAZAM False @@ -57,12 +57,12 @@ - + - - - - + + + + @@ -75,16 +75,16 @@ - + - - - + + + - + - + diff --git a/BLAZAM/GlobalUsings.cs b/BLAZAM/GlobalUsings.cs index 7079d615..f292a6c8 100644 --- a/BLAZAM/GlobalUsings.cs +++ b/BLAZAM/GlobalUsings.cs @@ -1,5 +1,6 @@ global using BLAZAM.Logger; global using BLAZAM.FileSystem; global using BLAZAM.Helpers; -global using BLAZAM.Common.Exceptions; +global using BLAZAM.Services.Background; + diff --git a/BLAZAM/Pages/Error/UnhandledExceptionPage.razor b/BLAZAM/Pages/Error/UnhandledExceptionPage.razor index c4fb7dc9..52ca979d 100644 --- a/BLAZAM/Pages/Error/UnhandledExceptionPage.razor +++ b/BLAZAM/Pages/Error/UnhandledExceptionPage.razor @@ -1,4 +1,3 @@ -@using BLAZAM.Email.Services; @inject EmailService email @inject ApplicationInfo ApplicationInfo @inject IAppDatabaseFactory factory diff --git a/BLAZAM/Pages/Groups/ConfirmNewGroup.razor b/BLAZAM/Pages/Groups/ConfirmNewGroup.razor index 8bdc049a..01839885 100644 --- a/BLAZAM/Pages/Groups/ConfirmNewGroup.razor +++ b/BLAZAM/Pages/Groups/ConfirmNewGroup.razor @@ -1,4 +1,6 @@ @inherits AppComponentBase +@inject OUNotificationService OUNotificationService + Confirm Group Creation @if (Group != null) @@ -41,6 +43,8 @@ } await AuditLogger.Group.Created(Group); + _ = OUNotificationService.PostAsync(Group, NotificationType.Create); + var commitJob = Group.CommitChanges(); await Confirmed.InvokeAsync(Group); } diff --git a/BLAZAM/Pages/Groups/CreateGroup.razor b/BLAZAM/Pages/Groups/CreateGroup.razor index 245f7242..9c017f3f 100644 --- a/BLAZAM/Pages/Groups/CreateGroup.razor +++ b/BLAZAM/Pages/Groups/CreateGroup.razor @@ -1,7 +1,6 @@ @page "/groups/create" @inherits TabbedAppComponentBase @attribute [Authorize] -@inject OUNotificationService OUNotificationService Create Group @@ -54,7 +53,7 @@ - + @@ -121,10 +120,4 @@ await InvokeAsync(StateHasChanged); } - async Task GroupCreated(IADGroup ou) - { - await AuditLogger.Group.Created(ou); - _ = OUNotificationService.PostAsync(ou, NotificationType.Create); - - } } diff --git a/BLAZAM/Pages/OU/ConfirmNewOU.razor b/BLAZAM/Pages/OU/ConfirmNewOU.razor index 6b436a8a..59de0d9d 100644 --- a/BLAZAM/Pages/OU/ConfirmNewOU.razor +++ b/BLAZAM/Pages/OU/ConfirmNewOU.razor @@ -1,4 +1,6 @@ @inherits AppComponentBase +@inject OUNotificationService OUNotificationService + Confirm OU Creation @if (OU != null) @@ -27,6 +29,8 @@ { await OU.CommitChangesAsync(); SnackBarService.Success("OU created"); + await AuditLogger.OU.Created(OU); + _ = OUNotificationService.PostAsync(OU, NotificationType.Create); await Confirmed.InvokeAsync(OU); Nav.NavigateTo("/ou/create",true); } diff --git a/BLAZAM/Pages/OU/CreateOU.razor b/BLAZAM/Pages/OU/CreateOU.razor index f560aac8..2917594e 100644 --- a/BLAZAM/Pages/OU/CreateOU.razor +++ b/BLAZAM/Pages/OU/CreateOU.razor @@ -1,7 +1,6 @@ @page "/ou/create" @inherits TabbedAppComponentBase @attribute [Authorize] -@inject OUNotificationService OUNotificationService Create OU @@ -37,7 +36,7 @@ - + @@ -118,10 +117,5 @@ await InvokeAsync(StateHasChanged); } - async Task OUCreated(IADOrganizationalUnit ou) - { - await AuditLogger.OU.Created(ou); - _ = OUNotificationService.PostAsync(ou, NotificationType.Create); - } } diff --git a/BLAZAM/Pages/Users/ViewUser.razor b/BLAZAM/Pages/Users/ViewUser.razor index 21741fc5..a90ec1d6 100644 --- a/BLAZAM/Pages/Users/ViewUser.razor +++ b/BLAZAM/Pages/Users/ViewUser.razor @@ -546,6 +546,7 @@ await RefreshEntryComponents(); try { + var changes = User.Changes; var jobResults = await User.CommitChangesAsync(); if (jobResults.Result == JobResult.Passed) @@ -553,8 +554,12 @@ await AuditLogger.User.Changed(User, changes); - if((changes.Count==1 && changes.First().Field==ActiveDirectoryFields.MemberOf.FieldName)==false) + if(changes.Any(c=>c.Field!=ActiveDirectoryFields.MemberOf.FieldName)) _ = OUNotificationService.PostAsync(User, NotificationType.Modify); + else + { + + } EditMode = false; Nav.WarnOnNavigation = false; SnackBarService.Success("The changes made to this user have been saved."); diff --git a/BLAZAM/ProgramHelpers.cs b/BLAZAM/ProgramHelpers.cs index 384bdc39..7a2f7b7d 100644 --- a/BLAZAM/ProgramHelpers.cs +++ b/BLAZAM/ProgramHelpers.cs @@ -1,34 +1,22 @@ using BLAZAM.Common.Data.Services; using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Localization; using MudBlazor.Services; using System.Globalization; using MudBlazor; -using BLAZAM.Server.Data; -using BLAZAM.Update.Services; -using BLAZAM.Update; using BLAZAM.Database.Context; -using BLAZAM.ActiveDirectory.Interfaces; -using BLAZAM.ActiveDirectory; using BLAZAM.Session.Interfaces; using BLAZAM.Notifications.Services; using BLAZAM.Common.Data; -using BLAZAM.Services.Background; -using BLAZAM.Email.Services; using BLAZAM.Services; using BLAZAM.Services.Duo; -using BLAZAM.Server.Data.Services; using System.Diagnostics; using System.Reflection; using BLAZAM.Services.Chat; using BLAZAM.Services.Audit; -using BLAZAM.Common; using BLAZAM.Nav; using BLAZAM.Session; using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Org.BouncyCastle.Ocsp; using System.Management; namespace BLAZAM.Server diff --git a/BLAZAMActiveDirectory/BLAZAMActiveDirectory.csproj b/BLAZAMActiveDirectory/BLAZAMActiveDirectory.csproj index 30c6322c..5d630802 100644 --- a/BLAZAMActiveDirectory/BLAZAMActiveDirectory.csproj +++ b/BLAZAMActiveDirectory/BLAZAMActiveDirectory.csproj @@ -15,6 +15,7 @@ + diff --git a/BLAZAMActiveDirectory/Helpers/ActiveDirectoryHelpers.cs b/BLAZAMActiveDirectory/Helpers/ActiveDirectoryHelpers.cs index cd7dd547..6a5df47b 100644 --- a/BLAZAMActiveDirectory/Helpers/ActiveDirectoryHelpers.cs +++ b/BLAZAMActiveDirectory/Helpers/ActiveDirectoryHelpers.cs @@ -43,7 +43,7 @@ public static IEnumerable MoveToTop(this IEnumerable mathingItems=new List(); - for (int x =1; x < list.Count(); x++) + for (int x =0; x < list.Count(); x++) { if (matchingPredicate.Invoke(list[x])) @@ -63,15 +63,7 @@ public static IEnumerable MoveToTop(this IEnumerable - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/BLAZAMCommon/BLAZAMCommon.csproj b/BLAZAMCommon/BLAZAMCommon.csproj index 8c1d33f6..ef1c3db0 100644 --- a/BLAZAMCommon/BLAZAMCommon.csproj +++ b/BLAZAMCommon/BLAZAMCommon.csproj @@ -20,7 +20,7 @@ - + @@ -33,7 +33,7 @@ - + diff --git a/BLAZAMDatabase/BLAZAMDatabase.csproj b/BLAZAMDatabase/BLAZAMDatabase.csproj index 5663a9ab..4d35f064 100644 --- a/BLAZAMDatabase/BLAZAMDatabase.csproj +++ b/BLAZAMDatabase/BLAZAMDatabase.csproj @@ -18,7 +18,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/BLAZAMDatabase/Context/DatabaseContextBase.cs b/BLAZAMDatabase/Context/DatabaseContextBase.cs index d4323bb1..f0fcbe1a 100644 --- a/BLAZAMDatabase/Context/DatabaseContextBase.cs +++ b/BLAZAMDatabase/Context/DatabaseContextBase.cs @@ -11,15 +11,12 @@ using BLAZAM.Logger; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Configuration; using BLAZAM.Database.Models.Chat; using BLAZAM.Server.Data; -using Microsoft.IdentityModel.Tokens; using System.Data; using BLAZAM.FileSystem; -using Microsoft.EntityFrameworkCore.ChangeTracking; using BLAZAM.Database.Models.Notifications; namespace BLAZAM.Database.Context diff --git a/BLAZAMDatabase/Models/Notifications/NotificationSubscription.cs b/BLAZAMDatabase/Models/Notifications/NotificationSubscription.cs index 4def18ee..e699b4a3 100644 --- a/BLAZAMDatabase/Models/Notifications/NotificationSubscription.cs +++ b/BLAZAMDatabase/Models/Notifications/NotificationSubscription.cs @@ -1,9 +1,4 @@ using BLAZAM.Database.Models.User; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace BLAZAM.Database.Models.Notifications { diff --git a/BLAZAMDatabase/Models/Permissions/ObjectAction.cs b/BLAZAMDatabase/Models/Permissions/ObjectAction.cs index b655024b..31779f4b 100644 --- a/BLAZAMDatabase/Models/Permissions/ObjectAction.cs +++ b/BLAZAMDatabase/Models/Permissions/ObjectAction.cs @@ -26,15 +26,14 @@ public bool IsActionAppropriateForObject(ActiveDirectoryObjectType type) switch (type) { case ActiveDirectoryObjectType.User: - return true; case ActiveDirectoryObjectType.Computer: switch (Name) { + case "Lock": + case "Unlock": case "Move": case "Delete": case "Create": - case "UnAssign": - case "Assign": case "Enable": case "Disable": case "Rename": @@ -55,6 +54,7 @@ public bool IsActionAppropriateForObject(ActiveDirectoryObjectType type) default: return false; } + case ActiveDirectoryObjectType.Printer: case ActiveDirectoryObjectType.OU: switch (Name) { @@ -66,6 +66,14 @@ public bool IsActionAppropriateForObject(ActiveDirectoryObjectType type) default: return false; } + case ActiveDirectoryObjectType.BitLocker: + switch (Name) + { + case "Delete": + return true; + default: + return false; + } default: return false; diff --git a/BLAZAMEmail/BLAZAMEmail.csproj b/BLAZAMEmail/BLAZAMEmail.csproj index 2197dd71..fa036196 100644 --- a/BLAZAMEmail/BLAZAMEmail.csproj +++ b/BLAZAMEmail/BLAZAMEmail.csproj @@ -9,7 +9,7 @@ - + @@ -18,4 +18,8 @@ + + + + diff --git a/BLAZAMEmailMessage/BLAZAMEmailMessage.csproj b/BLAZAMEmailMessage/BLAZAMEmailMessage.csproj index bafe9f20..84a8390e 100644 --- a/BLAZAMEmailMessage/BLAZAMEmailMessage.csproj +++ b/BLAZAMEmailMessage/BLAZAMEmailMessage.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -13,8 +13,8 @@ - - + + diff --git a/BLAZAMEmailMessage/Email/Notifications/EntryCreatedEmailMessage.razor b/BLAZAMEmailMessage/Email/Notifications/EntryCreatedEmailMessage.razor new file mode 100644 index 00000000..9abc47db --- /dev/null +++ b/BLAZAMEmailMessage/Email/Notifications/EntryCreatedEmailMessage.razor @@ -0,0 +1,28 @@ +@using BLAZAM.Helpers +@using System.Security +@inherits NotificationTemplateComponent + + + @AppLocalization["Active Directory object created"] + + + + EntryName + AppLocalization[" has been created."]) + + + + + + +@code{ + [Parameter] + public string EntryName { get; set; } + + public override string Render() => new ComponentRenderer() + .UseLayout() + .AddServiceProvider(ApplicationInfo.services) + .Set(c => c.EntryName, EntryName).Render(); +} + + + diff --git a/BLAZAMEmailMessage/Email/Notifications/EntryDeletedEmailMessage.razor b/BLAZAMEmailMessage/Email/Notifications/EntryDeletedEmailMessage.razor new file mode 100644 index 00000000..ef094124 --- /dev/null +++ b/BLAZAMEmailMessage/Email/Notifications/EntryDeletedEmailMessage.razor @@ -0,0 +1,28 @@ +@using BLAZAM.Helpers +@using System.Security +@inherits NotificationTemplateComponent + + + @AppLocalization["Object deleted"] + + + + @( EntryName + AppLocalization[" has been deltted."]) + + + + + + +@code{ + [Parameter] + public string EntryName { get; set; } + + public override string Render() => new ComponentRenderer() + .UseLayout() + .AddServiceProvider(ApplicationInfo.services) + .Set(c => c.EntryName, EntryName).Render(); +} + + + diff --git a/BLAZAMEmailMessage/Email/Notifications/EntryEditedEmailMessage.razor b/BLAZAMEmailMessage/Email/Notifications/EntryEditedEmailMessage.razor new file mode 100644 index 00000000..8ca483dd --- /dev/null +++ b/BLAZAMEmailMessage/Email/Notifications/EntryEditedEmailMessage.razor @@ -0,0 +1,28 @@ +@using BLAZAM.Helpers +@using System.Security +@inherits NotificationTemplateComponent + + + @AppLocalization["Entry modified"] + + + + @(EntryName + AppLocalization[" has been modified."]) + + + + + + +@code{ + [Parameter] + public string EntryName { get; set; } + + public override string Render() => new ComponentRenderer() + .UseLayout() + .AddServiceProvider(ApplicationInfo.services) + .Set(c => c.EntryName, EntryName).Render(); +} + + + diff --git a/BLAZAMEmailMessage/Email/Notifications/EntryGroupAssignmentEmailMessage.razor b/BLAZAMEmailMessage/Email/Notifications/EntryGroupAssignmentEmailMessage.razor new file mode 100644 index 00000000..ee922d5f --- /dev/null +++ b/BLAZAMEmailMessage/Email/Notifications/EntryGroupAssignmentEmailMessage.razor @@ -0,0 +1,28 @@ +@using BLAZAM.Helpers +@using System.Security +@inherits NotificationTemplateComponent + + + @AppLocalization["Group membership changed"] + + + + @(AppLocalization["he password for "] + EntryName + AppLocalization[" has been changed."]) + + + + + + +@code{ + [Parameter] + public string EntryName { get; set; } + + public override string Render() => new ComponentRenderer() + .UseLayout() + .AddServiceProvider(ApplicationInfo.services) + .Set(c => c.EntryName, EntryName).Render(); +} + + + diff --git a/BLAZAMGui/BLAZAMGui.csproj b/BLAZAMGui/BLAZAMGui.csproj index e135ad9a..0222df55 100644 --- a/BLAZAMGui/BLAZAMGui.csproj +++ b/BLAZAMGui/BLAZAMGui.csproj @@ -24,13 +24,13 @@ - + - - - + + + - + diff --git a/BLAZAMGui/Layouts/AppUserButton.razor b/BLAZAMGui/Layouts/AppUserButton.razor index 385c5510..5ca02aa6 100644 --- a/BLAZAMGui/Layouts/AppUserButton.razor +++ b/BLAZAMGui/Layouts/AppUserButton.razor @@ -34,6 +34,9 @@ @AppLocalization["Profile Settings"] + + @AppLocalization["Notification Settings"] + @AppLocalization["Documentation"] @@ -58,8 +61,14 @@ + + + + + @code { AppModal? profileModal; + AppModal? notificationsModal; /// /// Indicates whether the notification panel is open /// diff --git a/BLAZAMGui/UI/AppComponentBase.razor.cs b/BLAZAMGui/UI/AppComponentBase.razor.cs index 55ec62a9..e1f08866 100644 --- a/BLAZAMGui/UI/AppComponentBase.razor.cs +++ b/BLAZAMGui/UI/AppComponentBase.razor.cs @@ -1,9 +1,7 @@ using BLAZAM.ActiveDirectory; -using BLAZAM.Email.Services; using BLAZAM.Services.Audit; using BLAZAM.Services.Chat; -using BLAZAM.Common; using BLAZAM.Nav; namespace BLAZAM.Gui.UI @@ -44,8 +42,7 @@ public class AppComponentBase : ComponentBase,IDisposable [Inject] public ICurrentUserStateService CurrentUser { get; set; } - // protected IApplicationUserState? CurrentUser => UserStateService.CurrentUserState; - + [Inject] protected AuditLogger AuditLogger { get; set; } @@ -85,7 +82,6 @@ public class AppComponentBase : ComponentBase,IDisposable protected override void OnInitialized() { base.OnInitialized(); - //Nav = new AppNavigationManager(BaseNav); try { Context = DbFactory.CreateDbContext(); @@ -151,9 +147,7 @@ protected void Refresh(bool forceReload = false) public virtual void Dispose() { - //Remove for issue #235, Dependency Injection automatically - //disposes of objects after they are no longer needed. - //Context?.Dispose(); + //This object requires no further disposal } public async Task CopyToClipboard(string? text) diff --git a/BLAZAMGui/UI/AppModal.razor.cs b/BLAZAMGui/UI/AppModal.razor.cs index 0e5b1dbf..f570d415 100644 --- a/BLAZAMGui/UI/AppModal.razor.cs +++ b/BLAZAMGui/UI/AppModal.razor.cs @@ -131,9 +131,9 @@ protected override void OnInitialized() /// /// Re-renders the modal with the latest property values /// - public void RefreshView() + public async Task RefreshView() { - InvokeAsync(StateHasChanged); + await InvokeAsync(StateHasChanged); } /// diff --git a/BLAZAMGui/UI/AppModalContentBase.razor b/BLAZAMGui/UI/AppModalContentBase.razor index ac3755ef..bc2027f1 100644 --- a/BLAZAMGui/UI/AppModalContentBase.razor +++ b/BLAZAMGui/UI/AppModalContentBase.razor @@ -1,5 +1,4 @@ -@using BLAZAM.Email.Services; -@using BLAZAM.Services.Chat; +@using BLAZAM.Services.Chat; @code { diff --git a/BLAZAMGui/UI/Dashboard/CurrentUserDashboardWidgets.razor b/BLAZAMGui/UI/Dashboard/CurrentUserDashboardWidgets.razor index c812516b..4fe38219 100644 --- a/BLAZAMGui/UI/Dashboard/CurrentUserDashboardWidgets.razor +++ b/BLAZAMGui/UI/Dashboard/CurrentUserDashboardWidgets.razor @@ -40,18 +40,33 @@ @{ - var widget = allWidgets.First(w => w.WidgetType == context.WidgetType); - } - - - @widget.Title - - {await RemoveWidget(context);}) /> - - - + Widget? widget =null; + try + { + widget = allWidgets.First(w => w.WidgetType == context.WidgetType); + + } + catch + { + + } + if (widget != null) + { + + + @widget.Title + + {await RemoveWidget(context);}) /> + + + + + + } + } + } diff --git a/BLAZAMGui/UI/Dashboard/Widgets/AllWidgets.cs b/BLAZAMGui/UI/Dashboard/Widgets/AllWidgets.cs index 5b4caa78..defb9304 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/AllWidgets.cs +++ b/BLAZAMGui/UI/Dashboard/Widgets/AllWidgets.cs @@ -41,7 +41,7 @@ public static List Available(IApplicationUserState? applicationUser) widgets.Add(new NewComputersWidget() { WidgetType = DashboardWidgetType.NewComputers, Title = "Computers created in the last 14 days" }); if (applicationUser.IsSuperAdmin) { - widgets.Add(new ChangedPasswordsWidget() { WidgetType = DashboardWidgetType.PasswordsChanged, Title = "Password Changed" }); + //widgets.Add(new ChangedPasswordsWidget() { WidgetType = DashboardWidgetType.PasswordsChanged, Title = "Password Changed" }); widgets.Add(new DeletedEntriesWidget() { WidgetType = DashboardWidgetType.DeletedEntries, Title = "Entries deleted in the last 14 days" }); } diff --git a/BLAZAMGui/UI/Dashboard/Widgets/ChangedEntriesWidget.razor b/BLAZAMGui/UI/Dashboard/Widgets/ChangedEntriesWidget.razor index 019aa729..9f65b1cd 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/ChangedEntriesWidget.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/ChangedEntriesWidget.razor @@ -57,7 +57,7 @@ { var search = new ADSearch(); - search.Fields.Changed = DateTime.Now.AddDays(-1); + search.Fields.PasswordLastSet = DateTime.Now.AddDays(-1).ToFileTimeUtc().ToString(); changdEntries = (await search.SearchAsync()).Where(x => x.CanRead).ToList(); LoadingData = false; await InvokeAsync(StateHasChanged); diff --git a/BLAZAMGui/UI/Dashboard/Widgets/ChangedPasswordsWidget.razor b/BLAZAMGui/UI/Dashboard/Widgets/ChangedPasswordsWidget.razor index 78b06042..9d654d68 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/ChangedPasswordsWidget.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/ChangedPasswordsWidget.razor @@ -1,8 +1,46 @@ @inherits Widget @attribute [Authorize] - - User passwords changed in the last 90 days + + + + + + @context.Item?.CanonicalName + + + + + + @(((IADUser)context.Item).PasswordLastSet) + + + + + + + + + + + + + +@* + @foreach (var user in LockedUsers) @@ -21,7 +59,7 @@ } - + *@ @code { List LockedUsers = new(); diff --git a/BLAZAMGui/UI/Dashboard/Widgets/DeletedEntriesWidget.razor b/BLAZAMGui/UI/Dashboard/Widgets/DeletedEntriesWidget.razor index fe93b838..8bb5a0d7 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/DeletedEntriesWidget.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/DeletedEntriesWidget.razor @@ -56,16 +56,7 @@ } - void RowClicked(DataGridRowClickEventArgs args) - { - if (args.Item != null) - { - GoTo(args.Item); - } - } + - void GoTo(IDirectoryEntryAdapter args) - { - Nav.NavigateTo(args.SearchUri); - } + } diff --git a/BLAZAMGui/UI/Dashboard/Widgets/Widget.razor b/BLAZAMGui/UI/Dashboard/Widgets/Widget.razor index 36fb0916..175da2ed 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/Widget.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/Widget.razor @@ -5,4 +5,16 @@ public RenderFragment? WidgetContent { get; set; } public string Title{ get; set; } public DashboardWidgetType WidgetType{ get; set; } + + protected virtual void RowClicked(DataGridRowClickEventArgs args) + { + if (args.Item != null) + { + GoTo(args.Item); + } + } + protected virtual void GoTo(IDirectoryEntryAdapter args) + { + Nav.NavigateTo(args.SearchUri); + } } diff --git a/BLAZAMGui/UI/Modals/AppNewsItemDialog.razor b/BLAZAMGui/UI/Modals/AppNewsItemDialog.razor index 2cadf069..997a7ca4 100644 --- a/BLAZAMGui/UI/Modals/AppNewsItemDialog.razor +++ b/BLAZAMGui/UI/Modals/AppNewsItemDialog.razor @@ -1,7 +1,7 @@ @using ApplicationNews @inherits AppComponentBase - + @((MarkupString)Item.Body) @@ -12,11 +12,11 @@ @if (!Item.Link.IsNullOrEmpty()) { @AppLocalization["Link"] + Href="@Item.Link" + Target="_blank">@Item.Link } - - + + @@ -42,7 +42,7 @@ private async void Acknowledge() { var existingReadItem = CurrentUser.State.ReadNewsItems.FirstOrDefault(x => x.NewsItemId == Item.Id); - if (existingReadItem!=null) + if (existingReadItem != null) { existingReadItem.NewsItemUpdatedAt = Item.UpdatedAt; } diff --git a/BLAZAMGui/UI/Modals/AppUserProfileModalContent.razor b/BLAZAMGui/UI/Modals/AppUserProfileModalContent.razor index 7e7ce0b8..21dee518 100644 --- a/BLAZAMGui/UI/Modals/AppUserProfileModalContent.razor +++ b/BLAZAMGui/UI/Modals/AppUserProfileModalContent.razor @@ -27,9 +27,9 @@ @if (CurrentUser.State.Preferences.ProfilePicture != null) { @@ -57,10 +57,37 @@ await CurrentUser.State.SaveUserSettings(); + @code { [CascadingParameter] public MainLayout mainLayout { get; set; } + protected override void OnInitialized() + { + base.OnInitialized(); + Modal.SetYesText(AppLocalization["Save"]); + Modal.OnYes += SaveSettings; + Modal.YesEnabled = () => { return !LoadingData; }; + } + private async void SaveSettings() + { + LoadingData = true; + await Modal.RefreshView(); + if (await CurrentUser.State.SaveUserSettings()) + { + SnackBarService.Success(AppLocalization["Settings saved"]); + + } + else + { + SnackBarService.Warning(AppLocalization["Failed to save settings"]); + + } + LoadingData = false; + await Modal.RefreshView(); + + + } #nullable disable warnings async Task UploadProfilePicture(IBrowserFile profilePictureFile) { @@ -69,7 +96,6 @@ await CurrentUser.State.SaveUserSettings(); if (rawBytes != null) { CurrentUser.State.Preferences.ProfilePicture = rawBytes.ReizeRawImage(100, true); - await CurrentUser.State.SaveUserSettings(); } } } diff --git a/BLAZAMGui/UI/Outputs/ApplicationNewsProvider.razor b/BLAZAMGui/UI/Outputs/ApplicationNewsProvider.razor index 2e617b57..f9b40b15 100644 --- a/BLAZAMGui/UI/Outputs/ApplicationNewsProvider.razor +++ b/BLAZAMGui/UI/Outputs/ApplicationNewsProvider.razor @@ -27,7 +27,7 @@ - + Blazam @AppLocalization["News"] @foreach (var item in unreadItems.OrderByDescending(x => x.UpdatedAt)) { @item.Title - @if (item.Link != null) + @* @if (item.Link != null) { @item.Link - } + } *@ } diff --git a/BLAZAMGui/UI/Settings/EmailSettings.razor b/BLAZAMGui/UI/Settings/EmailSettings.razor index 10186cdd..5f501815 100644 --- a/BLAZAMGui/UI/Settings/EmailSettings.razor +++ b/BLAZAMGui/UI/Settings/EmailSettings.razor @@ -91,7 +91,7 @@ Send Test Email - @if (ApplicationInfo.InDebugMode) + @if (ApplicationInfo.InDebugMode && emailPreview!=null) { @code { #nullable disable warnings - string emailPreview; + string? emailPreview=null; BLAZAM.Database.Models.EmailSettings settings = new BLAZAM.Database.Models.EmailSettings(); string testRecipient; protected override async Task OnInitializedAsync() @@ -134,7 +134,8 @@ //message.User = user; //var html = message.Render(); //emailPreview = EmailService.PrepareHTMLForEmail(html); - emailPreview = EmailService.BuildMessage("BLAZAM Test Email", "to@test.com").HtmlBody; + if(EmailService.IsConfigured) + emailPreview = EmailService.BuildMessage("BLAZAM Test Email", "to@test.com").HtmlBody; LoadingData = false; await InvokeAsync(StateHasChanged); diff --git a/BLAZAMGui/UI/Settings/ManualApplicationUpdater.razor b/BLAZAMGui/UI/Settings/ManualApplicationUpdater.razor index 68ba1148..4e786d44 100644 --- a/BLAZAMGui/UI/Settings/ManualApplicationUpdater.razor +++ b/BLAZAMGui/UI/Settings/ManualApplicationUpdater.razor @@ -186,7 +186,6 @@ { MessageService.ShowMessage(output.ToDialogParameters(), AppLocalization["Update"]); await output.RunAsync(); - // SnackBarService.Success("Update started successfully. The web application will restart and update momentarily."); } await InvokeAsync(StateHasChanged); diff --git a/BLAZAMGui/UI/Settings/Notifications/EditNotificationSubscriptionRow.razor b/BLAZAMGui/UI/Settings/Notifications/EditNotificationSubscriptionRow.razor index 4c12b319..ba3436dd 100644 --- a/BLAZAMGui/UI/Settings/Notifications/EditNotificationSubscriptionRow.razor +++ b/BLAZAMGui/UI/Settings/Notifications/EditNotificationSubscriptionRow.razor @@ -1,4 +1,4 @@ - +@inject IStringLocalizer AppLocalization @foreach (var type in Enum.GetValues(typeof(NotificationType))) { @@ -11,7 +11,6 @@ ValueChanged=@((bool val)=>{ToggleType(originalEnum,val);}) Value="@(Subscription.NotificationTypes.FirstOrDefault(x=>x.NotificationType==originalEnum)!=null)" /> - } @@ -29,9 +28,13 @@ @if (Subscription.Id == 0) { - + + @AppLocalization["Create"] + } else @@ -40,10 +43,12 @@ diff --git a/BLAZAMGui/UI/Settings/Notifications/NotificaionSubscriptionEditor.razor b/BLAZAMGui/UI/Settings/Notifications/NotificaionSubscriptionEditor.razor new file mode 100644 index 00000000..8785e10c --- /dev/null +++ b/BLAZAMGui/UI/Settings/Notifications/NotificaionSubscriptionEditor.razor @@ -0,0 +1,34 @@ + + + + + @if (_selectedOU != null) + { + + + + } + + + + +@code{ + [Parameter] + public AppUser User {get;set;} + + IDirectoryEntryAdapter? _selectedOU = null; + + + private async void ouChanged(IDirectoryEntryAdapter entry) + { + var ou = (IADOrganizationalUnit)entry; + if (ou != null) + { + _selectedOU = ou; + await InvokeAsync(StateHasChanged); + } + } + +} \ No newline at end of file diff --git a/BLAZAMGui/UI/Settings/Notifications/NotificationSettings.razor b/BLAZAMGui/UI/Settings/Notifications/NotificationSettings.razor index 9e4b1a39..1a050404 100644 --- a/BLAZAMGui/UI/Settings/Notifications/NotificationSettings.razor +++ b/BLAZAMGui/UI/Settings/Notifications/NotificationSettings.razor @@ -1,5 +1,5 @@ @inherits AppComponentBase -@AppLocalization["Managee Notifications"] +@AppLocalization["Manage Notifications"] @if (_selectedUser != null) { - - - - - @if (_selectedOU != null) - { - - - - } - - - + } @code { - IDirectoryEntryAdapter? _selectedOU = null; IList Users = new List(); AppUser? _selectedUser = null; protected override async Task OnInitializedAsync() @@ -37,15 +22,7 @@ if (value == null) value = String.Empty; return Users.Where(x => x.Username.Contains(value)); } - private async void ouChanged(IDirectoryEntryAdapter entry) - { - var ou = (IADOrganizationalUnit)entry; - if (ou != null) - { - _selectedOU = ou; - await InvokeAsync(StateHasChanged); - } - } + diff --git a/BLAZAMGui/UI/Settings/Notifications/OUNotificationSubscriptions.razor b/BLAZAMGui/UI/Settings/Notifications/OUNotificationSubscriptions.razor index 1351b69f..ec471f73 100644 --- a/BLAZAMGui/UI/Settings/Notifications/OUNotificationSubscriptions.razor +++ b/BLAZAMGui/UI/Settings/Notifications/OUNotificationSubscriptions.razor @@ -2,28 +2,52 @@ @inject OUNotificationService ouNotificationService + + + @(AppLocalization["Notification Settings for "]+_ou.CanonicalName) + + + + + + @AppLocalization["Events"] + + + @AppLocalization["Delivery"] + + + @AppLocalization[" "] + + + @AppLocalization[" "] + + - + @{ + bool first = true; + } @foreach (var type in Enum.GetValues(typeof(NotificationType))) { var originalEnum = (NotificationType)type; - + @originalEnum.ToString() + first=false; + } - + @AppLocalization["In App"] @AppLocalization["To Email"] - + @AppLocalization["Block"] - + @AppLocalization["Save"] @@ -37,10 +61,24 @@ + OnDeleted="DeleteExisting" /> } } + else + { + + + + @AppLocalization["No subscriptions are set for this OU"] + + + } + + + + + @@ -50,10 +88,16 @@ - - @AppLocalization["Effective Notification Settings"] + + + + + + + @(AppLocalization["Effective Notification Settings for "]+_ou.CanonicalName) + @@ -217,6 +261,8 @@ if (changes > 0) { newSubscription = new(); + newSubscription.UserId = User.Id; + newSubscription.OU = OU.DN; SnackBarService.Success(AppLocalization["Saved notification subscription"]); UpdateSubscriptions(); diff --git a/BLAZAMGui/_Imports.razor b/BLAZAMGui/_Imports.razor index 22f193b6..b7d7a6de 100644 --- a/BLAZAMGui/_Imports.razor +++ b/BLAZAMGui/_Imports.razor @@ -33,6 +33,8 @@ @using BLAZAM.Logger @using BLAZAM.Notifications.Services +@using BLAZAM.Gui.UI.Settings.Notifications + @using BLAZAM.Services @using BLAZAM.Services.Background @using BLAZAM.Session.Interfaces diff --git a/BLAZAMJobs/BLAZAMJobs.csproj b/BLAZAMJobs/BLAZAMJobs.csproj index e0a6bcc6..b7983acf 100644 --- a/BLAZAMJobs/BLAZAMJobs.csproj +++ b/BLAZAMJobs/BLAZAMJobs.csproj @@ -7,6 +7,11 @@ BLAZAM.Jobs + + + + + diff --git a/BLAZAMJobs/Job.cs b/BLAZAMJobs/Job.cs index fb03d411..100a04a3 100644 --- a/BLAZAMJobs/Job.cs +++ b/BLAZAMJobs/Job.cs @@ -1,7 +1,4 @@ -using BLAZAM.Common.Data; -using BLAZAM.Database.Models.User; -using BLAZAM.Session.Interfaces; -using Microsoft.AspNetCore.Components; + namespace BLAZAM.Jobs { @@ -13,7 +10,7 @@ public class Job : JobStepBase, IJob, IJobStep private DateTime scheduledRunTime = DateTime.Now; private Timer? runScheduler; - public string? User { get; set; } + public string? User { get; set; } = "System"; private IList _steps = new List(); diff --git a/BLAZAMLoggers/BLAZAMLogger.csproj b/BLAZAMLoggers/BLAZAMLogger.csproj index b7fa8f9c..475406fc 100644 --- a/BLAZAMLoggers/BLAZAMLogger.csproj +++ b/BLAZAMLoggers/BLAZAMLogger.csproj @@ -9,9 +9,9 @@ - + - + diff --git a/BLAZAMNotifications/BLAZAMNotifications.csproj b/BLAZAMNotifications/BLAZAMNotifications.csproj index 44298634..23703469 100644 --- a/BLAZAMNotifications/BLAZAMNotifications.csproj +++ b/BLAZAMNotifications/BLAZAMNotifications.csproj @@ -8,7 +8,7 @@ - + diff --git a/BLAZAMNotifications/Notifications/NotificationTypeExtentions.cs b/BLAZAMNotifications/Notifications/NotificationTypeExtentions.cs index 975e4efb..87e21875 100644 --- a/BLAZAMNotifications/Notifications/NotificationTypeExtentions.cs +++ b/BLAZAMNotifications/Notifications/NotificationTypeExtentions.cs @@ -1,9 +1,4 @@ using BLAZAM.Database.Models.Notifications; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace BLAZAM.Notifications.Notifications { @@ -17,6 +12,19 @@ public static class NotificationTypeExtentions case NotificationType.PasswordChange: notificationTemplate = new PasswordChangedEmailMessage(); break; + case NotificationType.Create: + notificationTemplate = new EntryCreatedEmailMessage(); + break; + case NotificationType.Delete: + notificationTemplate = new EntryDeletedEmailMessage(); + break; + case NotificationType.Modify: + notificationTemplate = new EntryEditedEmailMessage(); + break; + case NotificationType.GroupAssignment: + notificationTemplate = new EntryGroupAssignmentEmailMessage(); + break; + } if(notificationTemplate != null) { diff --git a/BLAZAMServices/BLAZAMServices.csproj b/BLAZAMServices/BLAZAMServices.csproj index 19291ced..01b7856c 100644 --- a/BLAZAMServices/BLAZAMServices.csproj +++ b/BLAZAMServices/BLAZAMServices.csproj @@ -9,9 +9,10 @@ - + + diff --git a/BLAZAMEmail/Services/EmailService.cs b/BLAZAMServices/Background/EmailService.cs similarity index 89% rename from BLAZAMEmail/Services/EmailService.cs rename to BLAZAMServices/Background/EmailService.cs index 164ff8f4..57415d20 100644 --- a/BLAZAMEmail/Services/EmailService.cs +++ b/BLAZAMServices/Background/EmailService.cs @@ -5,28 +5,38 @@ using MailKit.Security; using Microsoft.AspNetCore.Components; using MimeKit; -using MimeKit.Text; using MimeKit.Utils; using BLAZAM.Database.Models; using BLAZAM.Database.Context; using BLAZAM.Helpers; using BLAZAM.Common.Exceptions; -using BLAZAM.Logger; using BLAZAM.EmailMessage; using BLAZAM.EmailMessage.Email; using BLAZAM.Common.Data; using BLAZAM.Static; -using PreMailer.Net; using BLAZAM.FileSystem; using BLAZAM.EmailMessage.Email.Base; +using System.Configuration; -namespace BLAZAM.Email.Services +namespace BLAZAM.Services.Background { public class EmailService { public static EmailService? Instance { get; set; } private IAppDatabaseFactory Factory { get; set; } + public bool IsConfigured + { + get + { + EmailSettings? settings = GetSettings(); + if (settings != null && settings.Valid()) + { + return true; + } + return false; + } + } public EmailService(IAppDatabaseFactory factory) { @@ -48,7 +58,7 @@ public EmailService(IAppDatabaseFactory factory) /// renders it, and returns the raw HTML /// /// - /// The provided can not have any Blazorise components, only base Blazor + /// The provided can use basic MudBlazor components and Blazor components /// /// /// @@ -122,12 +132,14 @@ private MimeMessage BuildMessage(string subject, string to, string body, string? { var email = new MimeMessage(); - EmailSettings? settings = GetSettings(); - if (settings != null && settings.Valid()) + if (IsConfigured) { - if (settings.UseSMTPAuth && settings.FromAddress.IsNullOrEmpty()) email.From.Add(MailboxAddress.Parse(settings.SMTPUsername)); - else email.From.Add(MailboxAddress.Parse(settings.FromAddress)); + EmailSettings? settings = GetSettings(); + if (settings.UseSMTPAuth && settings.FromAddress.IsNullOrEmpty()) email.Sender=MailboxAddress.Parse(settings.SMTPUsername); + else email.Sender=MailboxAddress.Parse(settings.FromAddress); + if(!settings.FromName.IsNullOrEmpty()) email.Sender.Name = settings.FromName; + email.From.Add(email.Sender); if (to != null) email.To.Add(MailboxAddress.Parse(to)); if (cc != null) email.Cc.Add(MailboxAddress.Parse(cc)); if (bcc != null) email.Bcc.Add(MailboxAddress.Parse(bcc)); @@ -165,7 +177,7 @@ public string PrepareHTMLForEmail(string body) { SystemFile css = new SystemFile(ApplicationInfo.applicationRoot + "\\wwwroot\\lib\\mudblazor\\css\\mudblazor.min.css"); var preMailer = new PreMailer.Net.PreMailer(body); - body = preMailer.MoveCssInline(stripIdAndClassAttributes: true,css:css.ReadAllText()).Html; + body = preMailer.MoveCssInline(stripIdAndClassAttributes: true, css: css.ReadAllText()).Html; return body; } @@ -220,7 +232,7 @@ public async Task SendMessage(string subject, NotificationTemplateComponen var client = await GetSmtpClientAsync(); - var message = BuildMessage(subject, to,body.Render(), cc, bcc); + var message = BuildMessage(subject, to, body.Render(), cc, bcc); return await TrySend(client, message); } @@ -230,7 +242,7 @@ public async Task SendMessage(string subject, NotificationTemplateComponen } - catch(Exception ex) + catch (Exception ex) { throw ex; } diff --git a/BLAZAMServices/Background/OUNotificationService.cs b/BLAZAMServices/Background/OUNotificationService.cs index ddedaf88..1dc895dc 100644 --- a/BLAZAMServices/Background/OUNotificationService.cs +++ b/BLAZAMServices/Background/OUNotificationService.cs @@ -2,17 +2,14 @@ using BLAZAM.Database.Context; using BLAZAM.Database.Models.Notifications; using BLAZAM.Database.Models.User; +using BLAZAM.EmailMessage.Email.Base; +using BLAZAM.EmailMessage.Email.Notifications; +using BLAZAM.Helpers; using BLAZAM.Localization; using BLAZAM.Logger; +using BLAZAM.Notifications.Notifications; using BLAZAM.Notifications.Services; -using BLAZAM.Session.Interfaces; -using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Localization; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace BLAZAM.Services.Background { @@ -21,12 +18,14 @@ public class OUNotificationService private IAppDatabaseFactory _databaseFactory; private readonly INotificationPublisher _notificationPublisher; private readonly IStringLocalizer _appLocalization; + private readonly EmailService _emailService; - public OUNotificationService(IAppDatabaseFactory databaseFactory,INotificationPublisher notificationPublisher, IStringLocalizerappLocalization) + public OUNotificationService(IAppDatabaseFactory databaseFactory, INotificationPublisher notificationPublisher, IStringLocalizer appLocalization, EmailService emailService) { _databaseFactory = databaseFactory; _notificationPublisher = notificationPublisher; _appLocalization = appLocalization; + _emailService = emailService; } private IDatabaseContext Context => _databaseFactory.CreateDbContext(); public async Task PostAsync(IDirectoryEntryAdapter source, NotificationType notificationType) @@ -37,6 +36,7 @@ public async Task PostAsync(IDirectoryEntryAdapter source, NotificationType noti notificationTitle = _appLocalization[source.ObjectType.ToString()] + " "; string notificationBody; + NotificationTemplateComponent? emailMessage = null; notificationBody = "" + source.CanonicalName + " "; switch (notificationType) @@ -44,29 +44,40 @@ public async Task PostAsync(IDirectoryEntryAdapter source, NotificationType noti case NotificationType.Create: notificationTitle += _appLocalization["Created"]; notificationBody += _appLocalization["was created at"] + source.Created.Value.ToLocalTime(); - + var createdMessage = NotificationType.Create.ToNotification(); + createdMessage.EntryName = source.CanonicalName; + emailMessage = createdMessage; break; - case NotificationType.Delete: + case NotificationType.Delete: notificationTitle += _appLocalization["Deleted"]; notificationBody += _appLocalization["was deleted at"] + source.LastChanged.Value.ToLocalTime(); - + var deletedMessage = NotificationType.Delete.ToNotification(); + deletedMessage.EntryName = source.CanonicalName; + emailMessage = deletedMessage; break; case NotificationType.Modify: notificationTitle += _appLocalization["Modified"]; notificationBody += _appLocalization["was modified at"] + source.LastChanged.Value.ToLocalTime(); - + var editedMessage = NotificationType.Modify.ToNotification(); + editedMessage.EntryName = source.CanonicalName; + emailMessage = editedMessage; break; case NotificationType.GroupAssignment: notificationTitle += _appLocalization["Group Membership Changed"]; notificationBody += _appLocalization["was modified at"] + source.LastChanged.Value.ToLocalTime(); - + + var groupMembershipMessage = NotificationType.GroupAssignment.ToNotification(); + groupMembershipMessage.EntryName = source.CanonicalName; + emailMessage = groupMembershipMessage; break; case NotificationType.PasswordChange: notificationTitle += _appLocalization["Password Reset"]; notificationBody += _appLocalization["had a password reset at"] + source.LastChanged.Value.ToLocalTime(); - + var passwordChangeMessage = NotificationType.PasswordChange.ToNotification(); + passwordChangeMessage.EntryName = source.CanonicalName; + emailMessage = passwordChangeMessage; break; - + } var notification = new NotificationMessage(); notification.Title = notificationTitle; @@ -74,6 +85,7 @@ public async Task PostAsync(IDirectoryEntryAdapter source, NotificationType noti notification.Dismissable = true; notification.Created = DateTime.Now; notification.Level = NotificationLevel.Info; + var _emailConfigured = _emailService.IsConfigured; foreach (var user in Context.UserSettings.ToList()) { @@ -81,7 +93,23 @@ public async Task PostAsync(IDirectoryEntryAdapter source, NotificationType noti var effectiveEmailSubscriptions = CalculateEffectiveEmailSubscriptions(user, source); if (effectiveInAppSubscriptions.NotificationTypes.Any(x => x.NotificationType == notificationType)) { - _notificationPublisher.PublishNotification(user, notification); + await _notificationPublisher.PublishNotification(user, notification); + } + if (effectiveEmailSubscriptions.NotificationTypes.Any(x => x.NotificationType == notificationType)) + { + if (emailMessage != null) + { + if (_emailConfigured && !user.Email.IsNullOrEmpty()) + { + await _emailService.SendMessage(notificationTitle, emailMessage, user.Email); + + } + } + else + { + var error = new ApplicationException(); + Loggers.SystemLogger.Error("Email message template was not found! {@Error}", error); + } } } } @@ -135,7 +163,8 @@ public NotificationSubscription CalculateEffectiveEmailSubscriptions(AppUser use } } - }catch (Exception ex) + } + catch (Exception ex) { Loggers.SystemLogger.Error("Error while parsing users for notification broadcast {@Error}", ex); } @@ -155,7 +184,7 @@ public NotificationSubscription CalculateEffectiveInAppSubscriptions(AppUser use effectiveInAppSubscription.OU = ou.DN; effectiveInAppSubscription.User = user; effectiveInAppSubscription.InApp = true; - + var userSubscriptions = context.NotificationSubscriptions.Where(x => x.DeletedAt == null && x.UserId == user.Id).ToList(); userSubscriptions = userSubscriptions.OrderBy(x => x.OU).ToList(); foreach (var sub in userSubscriptions) @@ -171,7 +200,7 @@ public NotificationSubscription CalculateEffectiveInAppSubscriptions(AppUser use effectiveInAppSubscription.NotificationTypes.RemoveAll(x => x.NotificationType == type.NotificationType); } } - + } else { @@ -185,7 +214,7 @@ public NotificationSubscription CalculateEffectiveInAppSubscriptions(AppUser use } } } - + } diff --git a/BLAZAMSession/ApplicationUserState.cs b/BLAZAMSession/ApplicationUserState.cs index 1cb17ea5..c1a893ef 100644 --- a/BLAZAMSession/ApplicationUserState.cs +++ b/BLAZAMSession/ApplicationUserState.cs @@ -7,7 +7,6 @@ using BLAZAM.Database.Models.User; using BLAZAM.Helpers; using BLAZAM.Logger; -using BLAZAM.Notifications.Services; using BLAZAM.Session.Interfaces; using Microsoft.AspNetCore.Authentication; using Microsoft.EntityFrameworkCore; @@ -78,20 +77,13 @@ public IList? Notifications public DateTime lastDataRefresh; public AppUser? userSettings { get; set; } - private readonly INotificationPublisher _notificationPublisher; private readonly IAppDatabaseFactory _dbFactory; - public ApplicationUserState(IAppDatabaseFactory factory, INotificationPublisher notificationPublisher) + public ApplicationUserState(IAppDatabaseFactory factory) { - _notificationPublisher = notificationPublisher; _dbFactory = factory; - //userSettings = new(); - _notificationPublisher.OnNotificationPublished += (notifications) => - { - if (notifications.Select(n => n.User).Contains(Preferences)) - GetUserSettingFromDB(); - }; + OnSettingsChanged += (state) => { if (Id == state.Id) { diff --git a/BLAZAMSession/ApplicationUserStateService.cs b/BLAZAMSession/ApplicationUserStateService.cs index 3a2ed11d..c604010f 100644 --- a/BLAZAMSession/ApplicationUserStateService.cs +++ b/BLAZAMSession/ApplicationUserStateService.cs @@ -3,7 +3,6 @@ using BLAZAM.Common.Data.Services; using BLAZAM.Database.Context; using BLAZAM.Logger; -using BLAZAM.Notifications.Services; using BLAZAM.Session.Interfaces; using Microsoft.AspNetCore.Components.Server.Circuits; using Microsoft.AspNetCore.Http; @@ -24,7 +23,6 @@ namespace BLAZAM.Server.Data.Services /// public class ApplicationUserStateService : IApplicationUserStateService { - private INotificationPublisher _notificationPublisher; public static IApplicationUserStateService Instance { get; private set; } @@ -68,10 +66,8 @@ public class ApplicationUserStateService : IApplicationUserStateService /// An HTTP Context Accessor to get the current ClaimsPrincipal of the current session. /// This Principal is persisted via the browser authentication cookie /// Database Context Factory for accessing the Authentication Setting - SessionTimeout - public ApplicationUserStateService(IHttpContextAccessor httpContextAccessor, IAppDatabaseFactory factory, - INotificationPublisher notificationPublisher) + public ApplicationUserStateService(IHttpContextAccessor httpContextAccessor, IAppDatabaseFactory factory) { - _notificationPublisher = notificationPublisher; Instance = this; _httpContextAccessor = httpContextAccessor; _factory = factory; @@ -240,7 +236,7 @@ public void RemoveUserState(IApplicationUserState state) public IApplicationUserState CreateUserState(ClaimsPrincipal user) { - return new ApplicationUserState(_factory, _notificationPublisher) { User = user }; + return new ApplicationUserState(_factory) { User = user }; } } } diff --git a/BLAZAMSession/BLAZAMSession.csproj b/BLAZAMSession/BLAZAMSession.csproj index c1cb444d..1c18bc9b 100644 --- a/BLAZAMSession/BLAZAMSession.csproj +++ b/BLAZAMSession/BLAZAMSession.csproj @@ -10,7 +10,6 @@ - diff --git a/BLAZAMThemes/BLAZAMThemes.csproj b/BLAZAMThemes/BLAZAMThemes.csproj index 2ede2c12..21aee388 100644 --- a/BLAZAMThemes/BLAZAMThemes.csproj +++ b/BLAZAMThemes/BLAZAMThemes.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/BLAZAMUpdate/ApplicationUpdate.cs b/BLAZAMUpdate/ApplicationUpdate.cs index 09666920..2f3fcf3c 100644 --- a/BLAZAMUpdate/ApplicationUpdate.cs +++ b/BLAZAMUpdate/ApplicationUpdate.cs @@ -188,6 +188,7 @@ public IJob GetUpdateJob() var stagingCheckStep = new JobStep("Check prepared files", (step) => { return UpdateStagingDirectory.Exists; }); var bakupStep = new JobStep("Create backup", Backup); var updateUpdaterStep = new JobStep("Apply Files", InitiateFileCopy); + var waitForRestart = new JobStep("Wait for completion...",Wait); updateJob.AddStep(cleanDownloadStep); updateJob.AddStep(downloadStep); updateJob.AddStep(cleanStageStep); @@ -207,8 +208,14 @@ public IJob GetUpdateJob() throw new ApplicationUpdateException("An unknown error caused the update to fail."); } - - private async Task InitiateFileCopy(JobStep? step) + private async Task Wait(JobStep? step) + { + while (true) + { + await Task.Delay(1000); + } + } + private async Task InitiateFileCopy(JobStep? step) { //All prerequisites met diff --git a/BLAZAMUpdate/BLAZAMUpdate.csproj b/BLAZAMUpdate/BLAZAMUpdate.csproj index 069c8553..111a5779 100644 --- a/BLAZAMUpdate/BLAZAMUpdate.csproj +++ b/BLAZAMUpdate/BLAZAMUpdate.csproj @@ -10,7 +10,7 @@ - + diff --git a/BLAZAMUpdate/GithubArtifacts.cs b/BLAZAMUpdate/GithubArtifacts.cs deleted file mode 100644 index ed3d7f95..00000000 --- a/BLAZAMUpdate/GithubArtifacts.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace BLAZAM.Update -{ - public class WorkflowRun - { - public int id { get; set; } - public int repository_id { get; set; } - public int head_repository_id { get; set; } - public string head_branch { get; set; } - public string head_sha { get; set; } - } - - public class Artifact - { - public int id { get; set; } - public string node_id { get; set; } - public string name { get; set; } - public int size_in_bytes { get; set; } - public string url { get; set; } - public string archive_download_url { get; set; } - public bool expired { get; set; } - public DateTime created_at { get; set; } - public DateTime expires_at { get; set; } - public DateTime updated_at { get; set; } - public WorkflowRun workflow_run { get; set; } - } - - public class ArtifactResponse - { - public int total_count { get; set; } - public List artifacts { get; set; } - } -} diff --git a/BLAZAMUpdate/Services/AutoUpdateService.cs b/BLAZAMUpdate/Services/AutoUpdateService.cs index fc8073fc..ca6f959d 100644 --- a/BLAZAMUpdate/Services/AutoUpdateService.cs +++ b/BLAZAMUpdate/Services/AutoUpdateService.cs @@ -181,41 +181,47 @@ private void CleanDirectories(object? state) private async void CheckForUpdate(object? state) { - try - { - var appSettings = (await factory.CreateDbContextAsync()).AppSettings.FirstOrDefault(); + IJob updateCheckJob = new Job("Check for Update"); + IJobStep checkForUpdateStep = new JobStep("Execute", async(step) => { + try + { + var appSettings = (await factory.CreateDbContextAsync()).AppSettings.FirstOrDefault(); - Loggers.UpdateLogger.Information("Checking for automatic update"); + Loggers.UpdateLogger.Information("Checking for automatic update"); - var latestUpdate = await updateService.GetUpdates(); - if (latestUpdate != null && latestUpdate.Version.NewerThan(_applicationInfo.RunningVersion)) - { - IsUpdateAvailable = true; - if (appSettings.AutoUpdate && appSettings.AutoUpdateTime != null) + var latestUpdate = await updateService.GetUpdates(); + if (latestUpdate != null && latestUpdate.Version.NewerThan(_applicationInfo.RunningVersion)) { - if (latestUpdate.PassesPrerequisiteChecks) - ScheduleUpdate(appSettings.AutoUpdateTime.Value, latestUpdate); - else + IsUpdateAvailable = true; + if (appSettings.AutoUpdate && appSettings.AutoUpdateTime != null) { - Loggers.UpdateLogger.Warning("Update failed prerequisite check, cancelling scheduling {@Error}", latestUpdate.PrequisiteMessage); + if (latestUpdate.PassesPrerequisiteChecks) + ScheduleUpdate(appSettings.AutoUpdateTime.Value, latestUpdate); + else + { + Loggers.UpdateLogger.Warning("Update failed prerequisite check, cancelling scheduling {@Error}", latestUpdate.PrequisiteMessage); + } } + + } + else + { + IsUpdateAvailable = false; + Cancel(); + Loggers.UpdateLogger.Information("No new updates found."); + } } - else + catch (Exception ex) { - IsUpdateAvailable = false; - Cancel(); - Loggers.UpdateLogger.Information("No new updates found."); - + Loggers.UpdateLogger.Error("Error while checking for auto update {@Error}", ex); } - - } - catch (Exception ex) - { - Loggers.UpdateLogger.Error("Error while checking for auto update {@Error}", ex); - } + return true; + }); + updateCheckJob.AddStep(checkForUpdateStep); + await updateCheckJob.RunAsync(); } public void Cancel() { @@ -227,44 +233,51 @@ public void Cancel() public void ScheduleUpdate(TimeSpan updateTimeOfDay, ApplicationUpdate updateToInstall) { - try + IJob scheduleUpdatteJob = new Job("Schedule Update"); + IJobStep scheduleStep = new JobStep("Execute", async (step) => { - bool justScheduled = ScheduledUpdateTime == DateTime.MinValue && ScheduledUpdate != updateToInstall; - if (ScheduledUpdate != updateToInstall) + try { - Loggers.UpdateLogger.Information("New update found: " + updateToInstall.Version); + bool justScheduled = ScheduledUpdateTime == DateTime.MinValue && ScheduledUpdate != updateToInstall; + if (ScheduledUpdate != updateToInstall) + { + Loggers.UpdateLogger.Information("New update found: " + updateToInstall.Version); - //Update availabled - var now = DateTime.Now; - ScheduledUpdateTime = new DateTime(now.Year, now.Month, now.Day, updateTimeOfDay.Hours, updateTimeOfDay.Minutes, updateTimeOfDay.Seconds); + //Update availabled + var now = DateTime.Now; + ScheduledUpdateTime = new DateTime(now.Year, now.Month, now.Day, updateTimeOfDay.Hours, updateTimeOfDay.Minutes, updateTimeOfDay.Seconds); - //Check if we're past the scheduled time this day - if (ScheduledUpdateTime < now) - { - ScheduledUpdateTime = ScheduledUpdateTime.AddDays(1); - } + //Check if we're past the scheduled time this day + if (ScheduledUpdateTime < now) + { + ScheduledUpdateTime = ScheduledUpdateTime.AddDays(1); + } - TimeSpan timeUntilUpdate = ScheduledUpdateTime - now; + TimeSpan timeUntilUpdate = ScheduledUpdateTime - now; - ScheduledUpdate = updateToInstall; + ScheduledUpdate = updateToInstall; - autoUpdateApplyTimer = new Timer(Update, null, (int)timeUntilUpdate.TotalMilliseconds, Timeout.Infinite); - Loggers.UpdateLogger.Information("Auto-update scheduled: " + timeUntilUpdate.TotalMinutes + "mins from now at " + ScheduledUpdateTime); - if (justScheduled) - { - Loggers.UpdateLogger.Debug("Update just scheduled"); - OnAutoUpdateQueued?.Invoke(ScheduledUpdateTime); + autoUpdateApplyTimer = new Timer(Update, null, (int)timeUntilUpdate.TotalMilliseconds, Timeout.Infinite); + Loggers.UpdateLogger.Information("Auto-update scheduled: " + timeUntilUpdate.TotalMinutes + "mins from now at " + ScheduledUpdateTime); + if (justScheduled) + { + Loggers.UpdateLogger.Debug("Update just scheduled"); + OnAutoUpdateQueued?.Invoke(ScheduledUpdateTime); - } + } + } } - } - catch (Exception ex) - { - Loggers.UpdateLogger.Error("Error during auto update scheduling {@Error}", ex); - } + catch (Exception ex) + { + Loggers.UpdateLogger.Error("Error during auto update scheduling {@Error}", ex); + } + return true; + }); + scheduleUpdatteJob.AddStep(scheduleStep); + scheduleUpdatteJob.Run(); } private async void Update(object? state) diff --git a/BLAZAMUpdate/Services/UpdateService.cs b/BLAZAMUpdate/Services/UpdateService.cs index f4572c78..b06fabac 100644 --- a/BLAZAMUpdate/Services/UpdateService.cs +++ b/BLAZAMUpdate/Services/UpdateService.cs @@ -1,18 +1,15 @@ using Octokit; -using BLAZAM.Common; using BLAZAM.Update.Exceptions; using BLAZAM.Logger; using BLAZAM.Helpers; using BLAZAM.Common.Data; using BLAZAM.Database.Context; using System.Security.Principal; -using System.Reflection.Metadata.Ecma335; using System.Diagnostics; using BLAZAM.Localization; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; -using System.Net.WebSockets; namespace BLAZAM.Update.Services { @@ -49,7 +46,7 @@ public class UpdateService : UpdateServiceBase protected readonly IHttpClientFactory httpClientFactory; private readonly ApplicationInfo _applicationInfo; - public UpdateService(IHttpClientFactory _clientFactory, ApplicationInfo applicationInfo, IAppDatabaseFactory? dbFactory = null, IStringLocalizer appLocalization=null) + public UpdateService(IHttpClientFactory _clientFactory, ApplicationInfo applicationInfo, IAppDatabaseFactory? dbFactory = null, IStringLocalizer appLocalization = null) { _dbFactory = dbFactory; httpClientFactory = _clientFactory; @@ -108,7 +105,8 @@ private async Task GetReleases() latestBranchRelease = branchReleases.FirstOrDefault(); //Store all other releases for use later AvailableUpdates.Clear(); - try { + try + { var betaStableReleases = releases.Where(r => r.TagName.Contains("Stable", StringComparison.OrdinalIgnoreCase)); foreach (var release in betaStableReleases) @@ -125,7 +123,7 @@ private async Task GetReleases() { Loggers.UpdateLogger.Error("Error trying to get beta releases {@Error}", ex); } - + foreach (var release in stableReleases) { //Get the release filename to prepare a version object @@ -139,63 +137,18 @@ private async Task GetReleases() var latestBranchUpdate = EncapsulateUpdate(latestBranchRelease, SelectedBranch); if (latestBranchUpdate.Branch != ApplicationReleaseBranches.Stable && latestBranchUpdate.Branch != "Stable") { - if (!AvailableUpdates.Contains(latestBranchUpdate)) - { - AvailableUpdates.Add(latestBranchUpdate); - } - + if (!AvailableUpdates.Contains(latestBranchUpdate)) + { + AvailableUpdates.Add(latestBranchUpdate); + } + } IncompatibleUpdates = AvailableUpdates.Where(x => !x.PassesPrerequisiteChecks).ToList(); foreach (var release in IncompatibleUpdates) { AvailableUpdates.Remove(release); } - ////Override branch if stable has more recent release - //if (latestStableUpdate!=null) - //{ - // if(latestBranchUpdate!=null) - // { - // if (latestStableUpdate.Version.NewerThan(latestBranchUpdate.Version)) - // { - // LatestUpdate = latestStableUpdate; - - // } - // else - // { - // LatestUpdate = latestBranchUpdate; - - // } - - // } - // else - // { - // LatestUpdate = latestStableUpdate; - - // } - - //} - //if (Debugger.IsAttached) - //{ - // ApplicationUpdate? testUpdate = EncapsulateUpdate(latestRelease, SelectedBranch); - - // testUpdate.PreRequisiteChecks.Add(new(() => { - // if (!ApplicationInfo.isUnderIIS && !PrerequisiteChecker.CheckForAspCore()) - // { - // testUpdate.PrequisiteMessage = "ASP NET Core 8 Runtime is missing."; - // return false; - - // } - // if (ApplicationInfo.isUnderIIS && !PrerequisiteChecker.CheckForAspCoreHosting()) - // { - // testUpdate.PrequisiteMessage = "ASP NET Core 8 Web Hosting Bundle is missing."; - // return false; - - // } - // return true; - // })); - // testUpdate.Version = new ApplicationVersion("1.0.0.2024.07.01.0000"); - // LatestUpdate = testUpdate; - //} + } /// @@ -212,9 +165,9 @@ private async Task SetBranch() { using var context = await _dbFactory.CreateDbContextAsync(); SelectedBranch = context.AppSettings.FirstOrDefault()?.UpdateBranch; - if(SelectedBranch == "Stable") + if (SelectedBranch == "Stable") { - context.AppSettings.FirstOrDefault().UpdateBranch= ApplicationReleaseBranches.Stable; + context.AppSettings.FirstOrDefault().UpdateBranch = ApplicationReleaseBranches.Stable; SelectedBranch = ApplicationReleaseBranches.Stable; context.SaveChanges(); } @@ -240,7 +193,7 @@ private async Task SetBranch() releaseVersion = new ApplicationVersion(filename.Substring(filename.IndexOf("-v") + 2)); - + if (releaseToEncapsulate != null && releaseVersion != null) @@ -253,13 +206,14 @@ private async Task SetBranch() }; var update = new ApplicationUpdate(_applicationInfo, _dbFactory) { Release = release }; - if(releaseVersion.NewerThan(new ApplicationVersion("0.9.99"))) + if (releaseVersion.NewerThan(new ApplicationVersion("0.9.99"))) { - update.PreRequisiteChecks.Add(new(() => { - if (!ApplicationInfo.isUnderIIS && !PrerequisiteChecker.CheckForAspCore()) + update.PreRequisiteChecks.Add(new(() => + { + if (!ApplicationInfo.isUnderIIS && !PrerequisiteChecker.CheckForAspCore()) { - if(AppLocalization!=null) - update.PrequisiteMessage = AppLocalization["ASP NET Core 8 Runtime is missing."]; + if (AppLocalization != null) + update.PrequisiteMessage = AppLocalization["ASP NET Core 8 Runtime is missing."]; else update.PrequisiteMessage = "ASP NET Core 8 Runtime is missing."; @@ -354,7 +308,7 @@ private bool TestCustomCredentials() private bool TestDirectoryCredentials() { - if(_dbFactory == null)return false; + if (_dbFactory == null) return false; using var context = _dbFactory.CreateDbContext(); //Prepare impersonation WindowsImpersonation? impersonation = null; diff --git a/BlazamUpdate/BLAZAMUpdate.csproj b/BlazamUpdate/BLAZAMUpdate.csproj index 069c8553..111a5779 100644 --- a/BlazamUpdate/BLAZAMUpdate.csproj +++ b/BlazamUpdate/BLAZAMUpdate.csproj @@ -10,7 +10,7 @@ - + diff --git a/PlaywrightTests/PlaywrightTests.csproj b/PlaywrightTests/PlaywrightTests.csproj index 75b48e6a..0518ae38 100644 --- a/PlaywrightTests/PlaywrightTests.csproj +++ b/PlaywrightTests/PlaywrightTests.csproj @@ -17,7 +17,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive