diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 43a4368a7..305bdb11d 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "dotnet-ef": { - "version": "7.0.1", + "version": "9.0.0", "commands": [ "dotnet-ef" ] diff --git a/BLAZAM/BLAZAM.csproj b/BLAZAM/BLAZAM.csproj index 7dd4fdb73..de789bb6c 100644 --- a/BLAZAM/BLAZAM.csproj +++ b/BLAZAM/BLAZAM.csproj @@ -1,12 +1,12 @@ - + net8.0 enable enable false - 1.2.1 - 2024.12.02.2252 + 1.2.2 + 2024.12.14.0307 false BLAZAM True @@ -64,19 +64,19 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + - + - + @@ -126,6 +126,9 @@ PreserveNewest + + Never + diff --git a/BLAZAM/Pages/API/v1/Templates.cs b/BLAZAM/Pages/API/v1/Templates.cs index cbdd0f6eb..e64f99f52 100644 --- a/BLAZAM/Pages/API/v1/Templates.cs +++ b/BLAZAM/Pages/API/v1/Templates.cs @@ -19,6 +19,7 @@ using BLAZAM.Services.Audit; using BLAZAM.Session.Interfaces; using System.Text.Json; +using BLAZAM.Common.Data.Database; namespace BLAZAM.Pages.API.v1 { @@ -173,8 +174,16 @@ public async Task Execute(int templateId, [FromBody] NewUserDetai { newUser = (IADUser)Directory.GetDirectoryEntryByDN(newUser.DN); await AuditLogger.User.Created(newUser); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await OUNotificationService.PostAsync(newUser, NotificationType.Create, CurrentUserState); - _ = OUNotificationService.PostAsync(newUser, NotificationType.Create, CurrentUserState); + } + else + { + _ = OUNotificationService.PostAsync(newUser, NotificationType.Create, CurrentUserState); + + } try { diff --git a/BLAZAM/Pages/Computers/ViewComputer.razor b/BLAZAM/Pages/Computers/ViewComputer.razor index c50977a8c..133599065 100644 --- a/BLAZAM/Pages/Computers/ViewComputer.razor +++ b/BLAZAM/Pages/Computers/ViewComputer.razor @@ -325,17 +325,46 @@ { await AuditLogger.Computer.Assigned(assignment.Member, assignment.Group); await AuditLogger.Group.MemberAdded(assignment.Group, assignment.Member); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(Computer, NotificationType.Assign, CurrentUser.State, assignment.Group); + + } + else + { + _ = NotificationGenerationService.PostAsync(Computer, NotificationType.Assign, CurrentUser.State, assignment.Group); + + } } foreach (var assignment in unassignFrom) { await AuditLogger.Computer.Unassigned(assignment.Member, assignment.Group); await AuditLogger.Group.MemberRemoved(assignment.Group, assignment.Member); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(Computer, NotificationType.Unassign, CurrentUser.State, assignment.Group); + + } + else + { + _ = NotificationGenerationService.PostAsync(Computer, NotificationType.Unassign, CurrentUser.State, assignment.Group); + + } } if (changes.Any(c => c.Field != ActiveDirectoryFields.MemberOf.FieldName)) { - _ = NotificationGenerationService.PostAsync(Computer, NotificationType.Modify, CurrentUser.State); await AuditLogger.User.Changed(Computer, changes.Where(c => c.Field != ActiveDirectoryFields.MemberOf.FieldName).ToList()); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(Computer, NotificationType.Modify, CurrentUser.State); + + } + else + { + _ = NotificationGenerationService.PostAsync(Computer, NotificationType.Modify, CurrentUser.State); + + } } diff --git a/BLAZAM/Pages/Configure/Audit.razor b/BLAZAM/Pages/Configure/Audit.razor index 8b10ccfde..5fe36d65b 100644 --- a/BLAZAM/Pages/Configure/Audit.razor +++ b/BLAZAM/Pages/Configure/Audit.razor @@ -156,13 +156,12 @@ - - - + + + - - - + + diff --git a/BLAZAM/Pages/Configure/Fields.razor b/BLAZAM/Pages/Configure/Fields.razor index fc1705c51..5b723e92d 100644 --- a/BLAZAM/Pages/Configure/Fields.razor +++ b/BLAZAM/Pages/Configure/Fields.razor @@ -15,15 +15,22 @@ EditTrigger="DataGridEditTrigger.Manual"> - + - + - + @@ -38,7 +45,8 @@ - + @@ -66,7 +74,9 @@ } - + 100000) Size="@Size.Small" @@ -77,7 +87,8 @@ - + @code { diff --git a/BLAZAM/Pages/Configure/LoginHistoryChart.razor b/BLAZAM/Pages/Configure/LoginHistoryChart.razor index f2b6404ac..53644c55b 100644 --- a/BLAZAM/Pages/Configure/LoginHistoryChart.razor +++ b/BLAZAM/Pages/Configure/LoginHistoryChart.razor @@ -7,11 +7,16 @@ ChartOptions="@ChartOptions"> @* *@ -@code{ +@code { + - [Parameter] - public ChartOptions ChartOptions { get; set; } = new() { InterpolationOption=InterpolationOption.Straight }; + public ChartOptions ChartOptions { get; set; } = new() + { + InterpolationOption = InterpolationOption.Straight + }; + + [Parameter] public DateTime EndDate { get; set; } = DateTime.Today; @@ -40,13 +45,14 @@ protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - - var startDate = EndDate.AddDays(-1*Days); + loginChart = new() { Name = AppLocalization["Daily Logins"] }; + uniqueUsersChart = new() { Name = AppLocalization["Daily Users"] }; + var startDate = EndDate.AddDays(-1 * Days); allDates = Enumerable.Range(0, (int)(EndDate - startDate).TotalDays + 1) .Select(d => startDate.AddDays(d)); using (var context = await DbFactory.CreateDbContextAsync()) { - + logonEntries = await context.LogonAuditLog.ToListAsync(); diff --git a/BLAZAM/Pages/Groups/ConfirmNewGroup.razor b/BLAZAM/Pages/Groups/ConfirmNewGroup.razor index 6ab8b18e7..4340a72fb 100644 --- a/BLAZAM/Pages/Groups/ConfirmNewGroup.razor +++ b/BLAZAM/Pages/Groups/ConfirmNewGroup.razor @@ -1,19 +1,21 @@ @inherits AppComponentBase -@inject NotificationGenerationService OUNotificationService +@inject NotificationGenerationService NotificationGenerationService -Confirm Group Creation +@AppLocalization["Confirm Group Creation"] @if (Group != null) { @Group.ADSPath - + - Create... + + @AppLocalization["Create"] + } @code { - #nullable disable warnings +#nullable disable warnings private bool disableCreateGroupButton = false; @@ -33,20 +35,28 @@ createGroupJob.StopOnFailedStep = true; createGroupJob.ShowJobDetailsDialog(MessageService); var result = await Group.CommitChangesAsync(createGroupJob); - + disableCreateGroupButton = false; await InvokeAsync(StateHasChanged); if (result.FailedSteps.Count == 0) { Group = (IADGroup)Directory.GetDirectoryEntryByDN(Group.DN); - SnackBarService.Success("Group created"); + SnackBarService.Success(AppLocalization["Group created"]); await AuditLogger.Group.Created(Group); - _ = OUNotificationService.PostAsync(Group, NotificationType.Create, CurrentUser.State); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(Group, NotificationType.Create, CurrentUser.State); + } + else + { + _= NotificationGenerationService.PostAsync(Group, NotificationType.Create, CurrentUser.State); + + } await Confirmed.InvokeAsync(Group); } - + } } } \ No newline at end of file diff --git a/BLAZAM/Pages/Groups/CreateGroup.razor b/BLAZAM/Pages/Groups/CreateGroup.razor index e02cb7496..24ff88dda 100644 --- a/BLAZAM/Pages/Groups/CreateGroup.razor +++ b/BLAZAM/Pages/Groups/CreateGroup.razor @@ -1,67 +1,71 @@ @page "/create/group" @inherits TabbedAppComponentBase @attribute [Authorize] -Create Group +@AppLocalization["Create Group"] - - - - - + + + + - - @* - @context.Name - *@ - + + @* + @context.Name + *@ + - + - - Next - - - - Create - - - - - - + + @AppLocalization["Next"] + + + + + @AppLocalization["Create"] + + + + + + - Next - - - - Assign - - - - - - - - - - - Confirm - - - - + + + + @AppLocalization["Next"] + + + + + @AppLocalization["Assign"] + + + + + + + + + + + @AppLocalization["Confirm"] + + + + @@ -76,8 +80,8 @@ - string newGroupName=""; - List templates= new(); + string newGroupName = ""; + List templates = new(); IADOrganizationalUnit? parentOU; IADGroup? newGroup; diff --git a/BLAZAM/Pages/Groups/ViewGroup.razor b/BLAZAM/Pages/Groups/ViewGroup.razor index fddddd9e3..6ec1a93d8 100644 --- a/BLAZAM/Pages/Groups/ViewGroup.razor +++ b/BLAZAM/Pages/Groups/ViewGroup.razor @@ -161,21 +161,47 @@ { await AuditLogger.User.Assigned(assignment.Member, assignment.Group); await AuditLogger.Group.MemberAdded(assignment.Group, assignment.Member); - _ = NotificationGenerationService.PostAsync(assignment.Member, NotificationType.GroupAssignment, CurrentUser.State, Group); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(assignment.Member, NotificationType.Assign, CurrentUser.State, Group); + } + else + { + _= NotificationGenerationService.PostAsync(assignment.Member, NotificationType.Assign, CurrentUser.State, Group); + + } } foreach (var assignment in unassignFrom) { await AuditLogger.User.Unassigned(assignment.Member, assignment.Group); await AuditLogger.Group.MemberRemoved(assignment.Group, assignment.Member); - _ = NotificationGenerationService.PostAsync(assignment.Member, NotificationType.GroupAssignment, CurrentUser.State, Group); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(assignment.Member, NotificationType.Unassign, CurrentUser.State, Group); + + } + else + { + _= NotificationGenerationService.PostAsync(assignment.Member, NotificationType.Unassign, CurrentUser.State, Group); + } } if (changes.Any(c => c.Field != "member")) { - _ = NotificationGenerationService.PostAsync(Group, NotificationType.Modify, CurrentUser.State); await AuditLogger.Group.Changed(Group, changes.Where(c => c.Field != ActiveDirectoryFields.MemberOf.FieldName).ToList()); + + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(Group, NotificationType.Modify, CurrentUser.State); + + } + else + { + _ = NotificationGenerationService.PostAsync(Group, NotificationType.Modify, CurrentUser.State); + + } } //await AuditLogger.Group.Changed(Group, Group.Changes); diff --git a/BLAZAM/Pages/OU/ConfirmNewOU.razor b/BLAZAM/Pages/OU/ConfirmNewOU.razor index 169c6e057..95f9548ca 100644 --- a/BLAZAM/Pages/OU/ConfirmNewOU.razor +++ b/BLAZAM/Pages/OU/ConfirmNewOU.razor @@ -1,7 +1,7 @@ @inherits AppComponentBase -@inject NotificationGenerationService OUNotificationService +@inject NotificationGenerationService NotificationGenerationService -Confirm OU Creation +@AppLocalization["Confirm OU Creation"] @if (OU != null) { @@ -9,7 +9,7 @@ @OU.ADSPath - Create... + @AppLocalization["Create"] } @code { @@ -30,10 +30,19 @@ var results = await OU.CommitChangesAsync(); if (results.FailedSteps.Count == 0) { - OU = (IADOrganizationalUnit)Directory.GetDirectoryEntryByDN(OU.DN); - SnackBarService.Success("OU created"); + OU = (IADOrganizationalUnit)Directory.OUs.FindOuByDN(OU.DN); + SnackBarService.Success(AppLocalization["OU created"]); await AuditLogger.OU.Created(OU); - _ = OUNotificationService.PostAsync(OU, NotificationType.Create, CurrentUser.State); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(OU, NotificationType.Create, CurrentUser.State); + + } + else + { + _ = NotificationGenerationService.PostAsync(OU, NotificationType.Create, CurrentUser.State); + + } await Confirmed.InvokeAsync(OU); Nav.NavigateTo("/ou/create", true); } diff --git a/BLAZAM/Pages/OU/CreateOU.razor b/BLAZAM/Pages/OU/CreateOU.razor index a4cb89237..4b0773300 100644 --- a/BLAZAM/Pages/OU/CreateOU.razor +++ b/BLAZAM/Pages/OU/CreateOU.razor @@ -17,7 +17,7 @@ - Create + @AppLocalization["Create"] @@ -27,7 +27,7 @@ - Confirm + @AppLocalization["Confirm"] diff --git a/BLAZAM/Pages/OU/ViewOU.razor b/BLAZAM/Pages/OU/ViewOU.razor index 732ee10ed..849f8f40f 100644 --- a/BLAZAM/Pages/OU/ViewOU.razor +++ b/BLAZAM/Pages/OU/ViewOU.razor @@ -95,8 +95,16 @@ EditMode = false; //Nav.WarnOnNavigation = false; await AuditLogger.OU.Changed(OU, changes); - _ = NotificationGenerationService.PostAsync(OU, NotificationType.Modify, CurrentUser.State); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(OU, NotificationType.Modify, CurrentUser.State); + } + else + { + _= NotificationGenerationService.PostAsync(OU, NotificationType.Modify, CurrentUser.State); + + } SnackBarService.Success(AppLocalization["The changes made to this ou have been saved."]); await RefreshEntryComponents(); diff --git a/BLAZAM/Pages/Recycle Bin/RecycleBin.razor b/BLAZAM/Pages/Recycle Bin/RecycleBin.razor index 5de689e1f..80bbe5952 100644 --- a/BLAZAM/Pages/Recycle Bin/RecycleBin.razor +++ b/BLAZAM/Pages/Recycle Bin/RecycleBin.razor @@ -20,17 +20,21 @@ SortMode="@SortMode.Multiple" Groupable="false"> - Recycle Bin + @AppLocalization["Recycle Bin"] - Restore Selected - + + @AppLocalization["Restore Selected"] + + - + @@ -38,13 +42,17 @@ - - - - + + + + - Restore + + @AppLocalization["Restore"] + diff --git a/BLAZAM/Pages/Users/ConfirmNewUser.razor b/BLAZAM/Pages/Users/ConfirmNewUser.razor index 98472eaf1..4c399f573 100644 --- a/BLAZAM/Pages/Users/ConfirmNewUser.razor +++ b/BLAZAM/Pages/Users/ConfirmNewUser.razor @@ -3,7 +3,7 @@ @using BLAZAM.EmailMessage.Email.Notifications @inherits DirectoryModelComponent @inject IJSRuntime JSRuntime -@inject NotificationGenerationService OUNotificationService +@inject NotificationGenerationService NotificationGenerationService Confirm User Creation @@ -291,8 +291,15 @@ else confirmed = true; await Confirmed.InvokeAsync(); await AuditLogger.User.Created(User); - _ = OUNotificationService.PostAsync(User, NotificationType.Create, CurrentUser.State); + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(User, NotificationType.Create, CurrentUser.State); + } + else + { + _ = NotificationGenerationService.PostAsync(User, NotificationType.Create, CurrentUser.State); + } try { if (DirectoryTemplate?.EffectiveSendWelcomeEmail == true) diff --git a/BLAZAM/Pages/Users/CreateUser.razor b/BLAZAM/Pages/Users/CreateUser.razor index 05eefedde..4d7586f8a 100644 --- a/BLAZAM/Pages/Users/CreateUser.razor +++ b/BLAZAM/Pages/Users/CreateUser.razor @@ -18,7 +18,7 @@ - Template + @AppLocalization["Template"] @@ -81,7 +81,7 @@ @AppLocalization["There are no templates available"] - Create One + @AppLocalization["Create One"] @@ -133,7 +133,7 @@ { usernameStepValid = true; } - + } } @@ -145,15 +145,20 @@ Back + OnClick="@(()=>{SelectedStep=1;})"> + @AppLocalization["Back"] + Next + Disabled="@(conflictingEntry !=null)" + OnClick="@(()=>{SelectedStep=3;})"> + @AppLocalization["Next"] + - + @AppLocalization["Fields"] @@ -164,7 +169,9 @@ DirectoryTemplate="SelectedTemplate" /> Back + OnClick="@(()=>{SelectedStep=2;})"> + @AppLocalization["Back"] + @@ -187,9 +194,13 @@ Back + OnClick="@(()=>{SelectedStep=3;})"> + @AppLocalization["Back"] + Next + OnClick="@(()=>{SelectedStep=7;})"> + @AppLocalization["Next"] + @@ -211,13 +222,17 @@ Back + OnClick="@(()=>{SelectedStep=0;})"> + @AppLocalization["Back"] + Next + await CreateCustomUser(); + selectedStep=6; + })"> + @AppLocalization["Next"] + @@ -236,7 +251,8 @@ selectedStep=6; @bind-ConfirmPassword=@customConfirmPassword @bind-Password=customPassword /> Back + OnClick="@(()=>{SelectedStep=4;})"> + @AppLocalization["Back"] - @AppLocalization["Next"] @@ -353,7 +368,7 @@ selectedStep=6; { LoadingData = true; await InvokeAsync(StateHasChanged); - newUser = SelectedTemplate.GenerateTemplateUser(newUserName,Directory); + newUser = SelectedTemplate.GenerateTemplateUser(newUserName, Directory); if (IsAdmin || SelectedTemplate.HasEditableFields()) { SelectedStep = 2; @@ -376,7 +391,7 @@ selectedStep=6; await InvokeAsync(StateHasChanged); } - + async Task SetTemplate(DirectoryTemplate selectedTemplate) { SelectedTemplate = selectedTemplate; diff --git a/BLAZAM/Pages/Users/ViewUser.razor b/BLAZAM/Pages/Users/ViewUser.razor index 370081651..1e07ee11b 100644 --- a/BLAZAM/Pages/Users/ViewUser.razor +++ b/BLAZAM/Pages/Users/ViewUser.razor @@ -666,7 +666,17 @@ { await AuditLogger.User.Assigned(assignment.Member, assignment.Group); await AuditLogger.Group.MemberAdded(assignment.Group, assignment.Member); - _ = NotificationGenerationService.PostAsync(User, NotificationType.GroupAssignment, CurrentUser.State, assignment.Group); + //Run synchronously if using sqlite + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(User, NotificationType.Assign, CurrentUser.State, assignment.Group); + + } + else + { + _ = NotificationGenerationService.PostAsync(User, NotificationType.Assign, CurrentUser.State, assignment.Group); + + } } @@ -674,13 +684,31 @@ { await AuditLogger.User.Unassigned(assignment.Member, assignment.Group); await AuditLogger.Group.MemberRemoved(assignment.Group, assignment.Member); - _ = NotificationGenerationService.PostAsync(User, NotificationType.GroupAssignment, CurrentUser.State, assignment.Group); + //Run synchronously if using sqlite + if (DbFactory.DatabaseType == DatabaseType.SQLite) + { + await NotificationGenerationService.PostAsync(User, NotificationType.Unassign, CurrentUser.State, assignment.Group); + + } + else + { + _ = NotificationGenerationService.PostAsync(User, NotificationType.Unassign, CurrentUser.State, assignment.Group); + + } } if (changes.Any(c => c.Field != ActiveDirectoryFields.MemberOf.FieldName)) { - _ = NotificationGenerationService.PostAsync(User, NotificationType.Modify, CurrentUser.State); await AuditLogger.User.Changed(User, changes.Where(c => c.Field != ActiveDirectoryFields.MemberOf.FieldName).ToList()); + + //Run synchronously if using sqlite + if(DbFactory.DatabaseType == DatabaseType.SQLite){ + await NotificationGenerationService.PostAsync(User, NotificationType.Modify, CurrentUser.State); + + }else{ + _ = NotificationGenerationService.PostAsync(User, NotificationType.Modify, CurrentUser.State); + + } } EditMode = false; diff --git a/BLAZAM/Pages/_Layout.cshtml b/BLAZAM/Pages/_Layout.cshtml index 64304cfaa..751bcf1a1 100644 --- a/BLAZAM/Pages/_Layout.cshtml +++ b/BLAZAM/Pages/_Layout.cshtml @@ -43,7 +43,7 @@ { An unhandled exception has occurred. See browser dev tools for details. - + } Reload 🗙 @@ -83,6 +83,27 @@ + + + @* + + + *@ + @@ -112,5 +133,6 @@ + \ No newline at end of file diff --git a/BLAZAM/ProgramHelpers.cs b/BLAZAM/ProgramHelpers.cs index 5fecbe240..187b063d3 100644 --- a/BLAZAM/ProgramHelpers.cs +++ b/BLAZAM/ProgramHelpers.cs @@ -143,7 +143,7 @@ public static WebApplicationBuilder InjectServices(this WebApplicationBuilder bu }); /* * Uncomment this to force a language - + CultureInfo culture = new CultureInfo("zh-Hans"); //CultureInfo culture = new CultureInfo("zh-Hans"); @@ -356,7 +356,9 @@ public static WebApplicationBuilder InjectServices(this WebApplicationBuilder bu { Title = "Blazam API", Version = "v1", - Description = "The official Blazam API documentation. Authorization is required for API access.", + Description = "The official Blazam API documentation." + + "
Authorization is required for API access." + + "
The \"Authorization\" header value must be \"Bearer {token}\"", License = new OpenApiLicense() { Name = "MIT License", Url = new Uri("https://github.com/Blazam-App/BLAZAM/blob/v1-Dev/LICENSE") }, Contact = new() { @@ -374,7 +376,7 @@ public static WebApplicationBuilder InjectServices(this WebApplicationBuilder bu // Configure Swagger to use JWT Bearer authorization var jwtSecurityScheme = new OpenApiSecurityScheme { - Description = "JWT Authorization header using the Bearer scheme.Example: \"Authorization: Bearer {token}\"", + Description = "Enter only the token supplied by Blazam", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, diff --git a/BLAZAM/wwwroot/css/site.css b/BLAZAM/wwwroot/css/site.css index 48bc83eee..6296ea2a9 100644 --- a/BLAZAM/wwwroot/css/site.css +++ b/BLAZAM/wwwroot/css/site.css @@ -176,4 +176,6 @@ a, .btn-link { } } - +#jsd-widget{ + position:relative !important; +} diff --git a/BLAZAM/wwwroot/img/maggie.png b/BLAZAM/wwwroot/img/maggie.png new file mode 100644 index 000000000..d1fdfe0b0 Binary files /dev/null and b/BLAZAM/wwwroot/img/maggie.png differ diff --git a/BLAZAM/wwwroot/jira/feature-request.html b/BLAZAM/wwwroot/jira/feature-request.html new file mode 100644 index 000000000..01c7872e8 --- /dev/null +++ b/BLAZAM/wwwroot/jira/feature-request.html @@ -0,0 +1,42 @@ + + + + + + + + Report feedback
+ + + + + + + diff --git a/BLAZAM/wwwroot/js/blazam.js b/BLAZAM/wwwroot/js/blazam.js index 66f7d802d..be50a7d70 100644 --- a/BLAZAM/wwwroot/js/blazam.js +++ b/BLAZAM/wwwroot/js/blazam.js @@ -85,22 +85,12 @@ window.createGauge = async (id,maxValue) => { window.setGaugeValue = async (id, val, time) => { dialGauges[id].setValueAnimated(val, time); } -//const listener = (e) => { -// e.preventDefault(); -// e.returnValue = ''; -// return false; -//} -//window.warnOnNavigation = async (active) => { -// if (active) { -// window.addEventListener('beforeunload', listener); -// //window.popstate = listener; -// //window.addEventListener('popstate', listener); -// } else { -// window.removeEventListener('beforeunload', listener); -// //window.removeEventListener('beforepopstate', listener); -// } +//window.openFeatureRequestDialog = async () => { +// // Create a new Event object +// const event = new Event('openFeatureRequestDialog'); - +// // Dispatch the event on the document object +// document.dispatchEvent(event); //} diff --git a/BLAZAMCommon/BLAZAMCommon.csproj b/BLAZAMCommon/BLAZAMCommon.csproj index 9017ba08f..b4c52a11c 100644 --- a/BLAZAMCommon/BLAZAMCommon.csproj +++ b/BLAZAMCommon/BLAZAMCommon.csproj @@ -33,7 +33,7 @@ - + diff --git a/BLAZAMDatabase/Context/AppDatabaseFactory.cs b/BLAZAMDatabase/Context/AppDatabaseFactory.cs index 54ef4025e..7a478b300 100644 --- a/BLAZAMDatabase/Context/AppDatabaseFactory.cs +++ b/BLAZAMDatabase/Context/AppDatabaseFactory.cs @@ -178,7 +178,30 @@ private bool CheckInstallation() /// /// public async Task CreateDbContextAsync() => await Task.Run(() => { return CreateDbContext(); }); + public DatabaseType DatabaseType + { + get + { + var _dbType = _configuration.GetValue("DatabaseType"); + if (_dbType == null) throw new DatabaseException("DatabaseType missing in configuration file"); + // Console.WriteLine("Database Type: " + _dbType); + IDatabaseContext? databaseContext = null; + switch (_dbType.ToLower()) + { + + case "sql": + return DatabaseType.SQL; + case "sqlite": + + return DatabaseType.SQLite; + case "mysql": + return DatabaseType.MySQL; + + } + return DatabaseType.SQLite; + } + } /// /// Creates a new application based on the configured DatabaseType /// and DBConnectionString in appsettings.json @@ -194,30 +217,28 @@ private bool CheckInstallation() /// Thrown for unexpected exceptions public IDatabaseContext CreateDbContext() { - var _dbType = _configuration.GetValue("DatabaseType"); - if (_dbType == null) throw new DatabaseException("DatabaseType missing in configuration file"); - // Console.WriteLine("Database Type: " + _dbType); + IDatabaseContext? databaseContext = null; - switch (_dbType.ToLower()) + switch (DatabaseType) { - case "sql": + case DatabaseType.SQL: databaseContext = new SqlDatabaseContext(new DatabaseConnectionString(_configuration.GetConnectionString("DBConnectionString"), DatabaseType.SQL)); break; - case "sqlite": + case DatabaseType.SQLite: databaseContext = new SqliteDatabaseContext(new DatabaseConnectionString(_configuration.GetConnectionString("DBConnectionString"), DatabaseType.SQLite)); break; - case "mysql": + case DatabaseType.MySQL: databaseContext = new MySqlDatabaseContext(new DatabaseConnectionString(_configuration.GetConnectionString("DBConnectionString"), DatabaseType.MySQL)); break; } return databaseContext == null ? throw new Exception("Database Context is null. Attempted connection to a " - + _dbType + " type database") + + DatabaseType + " type database") : databaseContext; } diff --git a/BLAZAMDatabase/Context/IAppDatabaseFactory.cs b/BLAZAMDatabase/Context/IAppDatabaseFactory.cs index 1ad491337..d94834254 100644 --- a/BLAZAMDatabase/Context/IAppDatabaseFactory.cs +++ b/BLAZAMDatabase/Context/IAppDatabaseFactory.cs @@ -1,4 +1,5 @@ -using BLAZAM.Database.Exceptions; +using BLAZAM.Common.Data.Database; +using BLAZAM.Database.Exceptions; namespace BLAZAM.Database.Context { @@ -9,6 +10,8 @@ namespace BLAZAM.Database.Context /// public interface IAppDatabaseFactory { + DatabaseType DatabaseType { get; } + /// /// Applies any pending database migrations to the database synchronously /// diff --git a/BLAZAMDatabase/Context/SqliteDatabaseContext.cs b/BLAZAMDatabase/Context/SqliteDatabaseContext.cs index 59a56aa48..4ba85f623 100644 --- a/BLAZAMDatabase/Context/SqliteDatabaseContext.cs +++ b/BLAZAMDatabase/Context/SqliteDatabaseContext.cs @@ -25,7 +25,16 @@ public SqliteDatabaseContext(DbContextOptions options) : base(options) - + public override async Task SaveChangesAsync(CancellationToken cancellationToken = default) + { + try + { + return await base.SaveChangesAsync(cancellationToken); + }catch(Exception ex) + { + return -1; + } + } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { diff --git a/BLAZAMDatabase/Models/Notifications/NotificationType.cs b/BLAZAMDatabase/Models/Notifications/NotificationType.cs index 404f7bca6..243cb70a3 100644 --- a/BLAZAMDatabase/Models/Notifications/NotificationType.cs +++ b/BLAZAMDatabase/Models/Notifications/NotificationType.cs @@ -6,6 +6,6 @@ namespace BLAZAM.Database.Models.Notifications { - public enum NotificationType { Create, Delete, Modify, GroupAssignment, PasswordChange } + public enum NotificationType { Create, Delete, Modify, Unassign, Assign, PasswordChange } } diff --git a/BLAZAMEmailMessage/Email/Notifications/EntryGroupAssignmentEmailMessage.razor b/BLAZAMEmailMessage/Email/Notifications/EntryAssignedEmailMessage.razor similarity index 72% rename from BLAZAMEmailMessage/Email/Notifications/EntryGroupAssignmentEmailMessage.razor rename to BLAZAMEmailMessage/Email/Notifications/EntryAssignedEmailMessage.razor index ee922d5f8..f829b2971 100644 --- a/BLAZAMEmailMessage/Email/Notifications/EntryGroupAssignmentEmailMessage.razor +++ b/BLAZAMEmailMessage/Email/Notifications/EntryAssignedEmailMessage.razor @@ -3,11 +3,11 @@ @inherits NotificationTemplateComponent - @AppLocalization["Group membership changed"] + @AppLocalization["Group member addeed"] - @(AppLocalization["he password for "] + EntryName + AppLocalization[" has been changed."]) + @EntryName @AppLocalization["has been assigned to"])
@@ -18,7 +18,7 @@ [Parameter] public string EntryName { get; set; } - public override string Render() => new ComponentRenderer() + public override string Render() => new ComponentRenderer() .UseLayout() .AddServiceProvider(ApplicationInfo.services) .Set(c => c.EntryName, EntryName).Render(); diff --git a/BLAZAMEmailMessage/Email/Notifications/EntryUnassignedEmailMessage.razor b/BLAZAMEmailMessage/Email/Notifications/EntryUnassignedEmailMessage.razor new file mode 100644 index 000000000..4b8c7d849 --- /dev/null +++ b/BLAZAMEmailMessage/Email/Notifications/EntryUnassignedEmailMessage.razor @@ -0,0 +1,28 @@ +@using BLAZAM.Helpers +@using System.Security +@inherits NotificationTemplateComponent + + + @AppLocalization["Group member removed"] + + + + @EntryName @AppLocalization["has been unassigned from"]) +
+ + +
+ + +@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/Copyright.razor b/BLAZAMGui/Copyright.razor index efd7887c3..eaa6b2e61 100644 --- a/BLAZAMGui/Copyright.razor +++ b/BLAZAMGui/Copyright.razor @@ -3,12 +3,16 @@ - - BLAZAM™ @DateTime.Now.Year + + + + BLAZAM™ @DateTime.Now.Year + @code { - + [Parameter] + public EventCallback OnClick { get; set; } } diff --git a/BLAZAMGui/Layouts/AppFooter.razor b/BLAZAMGui/Layouts/AppFooter.razor index 854d483c0..f99851df9 100644 --- a/BLAZAMGui/Layouts/AppFooter.razor +++ b/BLAZAMGui/Layouts/AppFooter.razor @@ -2,24 +2,24 @@ @inherits AppComponentBase - + @if (AutoUpdateService.IsUpdatedScheduled) { {Nav.NavigateTo("/settings/update");}) - Class="mud-theme-info" - - Style="width:max-content" - Text="An automatic update is scheduled. Click for details"> + Class="mud-theme-info" + + Style="width:max-content" + Text="An automatic update is scheduled. Click for details"> + Style="width:max-content" + Text="An automatic update is scheduled."> @@ -36,6 +36,12 @@ + + + @code { [Parameter] public string? Class { get; set; } @@ -45,4 +51,6 @@ base.OnInitialized(); } + + AppModal? aboutModal; } \ No newline at end of file diff --git a/BLAZAMGui/Layouts/AppUserButton.razor b/BLAZAMGui/Layouts/AppUserButton.razor index c85a67875..c78a913bf 100644 --- a/BLAZAMGui/Layouts/AppUserButton.razor +++ b/BLAZAMGui/Layouts/AppUserButton.razor @@ -37,6 +37,10 @@ Icon="@Icons.Material.Filled.Api"> @AppLocalization["API"] +@* + @AppLocalization["Feature Request"] + *@ @if (UserState?.Impersonator == null) { diff --git a/BLAZAMGui/Navs/NavMenu.razor b/BLAZAMGui/Navs/NavMenu.razor index 3f6439e8d..3d278fcf9 100644 --- a/BLAZAMGui/Navs/NavMenu.razor +++ b/BLAZAMGui/Navs/NavMenu.razor @@ -95,7 +95,7 @@ - @AppLocalization["Api Tokens"] + @AppLocalization["API Tokens"] - + @context.Item?.Username @@ -38,7 +38,7 @@ - + @context.Item?.Timestamp.ToLocalTime() diff --git a/BLAZAMGui/UI/Dashboard/Widgets/ChangedEntriesWidget.razor b/BLAZAMGui/UI/Dashboard/Widgets/ChangedEntriesWidget.razor index 73868a8c1..1e0af58db 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/ChangedEntriesWidget.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/ChangedEntriesWidget.razor @@ -16,14 +16,14 @@ Class="py-0" SortMode="SortMode.Single"> - + - + diff --git a/BLAZAMGui/UI/Dashboard/Widgets/DeletedEntriesWidget.razor b/BLAZAMGui/UI/Dashboard/Widgets/DeletedEntriesWidget.razor index d625326ca..faeb17042 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/DeletedEntriesWidget.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/DeletedEntriesWidget.razor @@ -17,7 +17,7 @@ Class="py-0" SortMode="SortMode.Single"> - + @@ -26,14 +26,14 @@ - + @context.Item?.CanonicalName - + diff --git a/BLAZAMGui/UI/Dashboard/Widgets/FavoritesWidget.razor b/BLAZAMGui/UI/Dashboard/Widgets/FavoritesWidget.razor index 98db90e04..5d669a831 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/FavoritesWidget.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/FavoritesWidget.razor @@ -17,14 +17,14 @@ Class="py-0" SortMode="SortMode.Single"> - + - + diff --git a/BLAZAMGui/UI/Dashboard/Widgets/LockedOutUsers.razor b/BLAZAMGui/UI/Dashboard/Widgets/LockedOutUsers.razor index 9ab2c2c67..360b62c2f 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/LockedOutUsers.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/LockedOutUsers.razor @@ -16,7 +16,7 @@ Class="py-0" SortMode="SortMode.Single"> - + @@ -35,7 +35,7 @@ - + @if (context.Item?.LockoutTime != null) { diff --git a/BLAZAMGui/UI/Modals/AboutAppModal.razor b/BLAZAMGui/UI/Modals/AboutAppModal.razor deleted file mode 100644 index f2a49b520..000000000 --- a/BLAZAMGui/UI/Modals/AboutAppModal.razor +++ /dev/null @@ -1,27 +0,0 @@ - -@code { - -} diff --git a/BLAZAMGui/UI/Modals/AboutAppModalContent.razor b/BLAZAMGui/UI/Modals/AboutAppModalContent.razor new file mode 100644 index 000000000..3fb2720ec --- /dev/null +++ b/BLAZAMGui/UI/Modals/AboutAppModalContent.razor @@ -0,0 +1,50 @@ +@inherits AppModalContent + + + + + @AppLocalization["Founder"]: Chris Jacobsen + + + + @AppLocalization["Founded"]: 2022 + + + @AppLocalization["Version"]: @ApplicationInfo.RunningVersion.ToString() + + + + blazam.org + + + + Source Code + + + + + + + + + + + + + @AppLocalization["Dedicated To"] Maggie + @AppLocalization["In Loving Memory"] + 2014-2024 + + +@code { + protected override void OnInitialized() + { + + // Modal.OnYes = SaveChanges; + Modal.YesText = AppLocalization["Close"]; + base.OnInitialized(); + + + } + +} diff --git a/BLAZAMGui/UI/OU/MoveToOUModalContent.razor b/BLAZAMGui/UI/OU/MoveToOUModalContent.razor index 21aa0ec2b..6775aaa8b 100644 --- a/BLAZAMGui/UI/OU/MoveToOUModalContent.razor +++ b/BLAZAMGui/UI/OU/MoveToOUModalContent.razor @@ -25,7 +25,7 @@ StartingOU = (IADOrganizationalUnit)DirectoryModel.GetParent(); Modal.OnYes = MoveTo; Modal.YesText = AppLocalization["Move"]; - Modal.Title = "Move To"; + Modal.Title = AppLocalization["Move To"]; } @@ -40,8 +40,7 @@ { - // if (await MessageService.Confirm("Are you sure you want to move this " + DirectoryModel.ObjectType.ToString().ToLower() + " to " + SelectedOU.CanonicalName, "Confirm move")) - // { + var ouMovedFrom = DirectoryModel.GetParent() as IADOrganizationalUnit; DirectoryModel.MoveTo(ouToMoveTo); @@ -53,8 +52,6 @@ Close(); return; - - //} } } diff --git a/BLAZAMGui/UI/Outputs/AppTooltip.razor b/BLAZAMGui/UI/Outputs/AppTooltip.razor index 658a354d2..fa01fb9e6 100644 --- a/BLAZAMGui/UI/Outputs/AppTooltip.razor +++ b/BLAZAMGui/UI/Outputs/AppTooltip.razor @@ -1,22 +1,22 @@ @inherits MudTooltip +Arrow=@Arrow +Class="@Class" +Delay="@Delay" +Disabled=@Disabled +Duration="@Duration" +Inline=@Inline +Placement="@Placement" +RootClass="@RootClass" +RootStyle="@RootStyle" +ShowOnClick=@ShowOnClick +ShowOnFocus=@ShowOnFocus +ShowOnHover=@ShowOnHover +Style="@Style" +Tag="@Tag" +UserAttributes="@UserAttributes" +Visible=@Visible +VisibleChanged="@VisibleChanged"> @if (Text.IsNullOrEmpty()) { @@ -25,11 +25,12 @@ else { @Text + Color="@TextColor">@Text } - @ChildContent + @ChildContent + diff --git a/BLAZAMGui/UI/Settings/Notifications/EditNotificationSubscriptionRow.razor b/BLAZAMGui/UI/Settings/Notifications/EditNotificationSubscriptionRow.razor index 096c72b12..f25166325 100644 --- a/BLAZAMGui/UI/Settings/Notifications/EditNotificationSubscriptionRow.razor +++ b/BLAZAMGui/UI/Settings/Notifications/EditNotificationSubscriptionRow.razor @@ -1,12 +1,20 @@ @inject IStringLocalizer AppLocalization + + + {ToggleType(NotificationType.Assign,val);ToggleType(NotificationType.Unassign,val);}) + Value="@(Subscription.NotificationTypes.FirstOrDefault(x=>x.NotificationType==NotificationType.Assign)!=null)" /> + + @foreach (var type in Enum.GetValues(typeof(NotificationType))) { + var originalEnum = (NotificationType)type; + if(originalEnum== NotificationType.Unassign || originalEnum == NotificationType.Assign){ + continue; + } - @{ - - } {ToggleType(originalEnum,val);}) Value="@(Subscription.NotificationTypes.FirstOrDefault(x=>x.NotificationType==originalEnum)!=null)" /> diff --git a/BLAZAMGui/UI/Settings/Notifications/OUNotificationSubscriptions.razor b/BLAZAMGui/UI/Settings/Notifications/OUNotificationSubscriptions.razor index f6211fd51..7a3711b65 100644 --- a/BLAZAMGui/UI/Settings/Notifications/OUNotificationSubscriptions.razor +++ b/BLAZAMGui/UI/Settings/Notifications/OUNotificationSubscriptions.razor @@ -25,17 +25,21 @@ - - @{ - bool first = true; - } + + @AppLocalization["Group Membership Changes"] + + @foreach (var type in Enum.GetValues(typeof(NotificationType))) { + var originalEnum = (NotificationType)type; - + if (originalEnum == NotificationType.Unassign || originalEnum == NotificationType.Assign) + { + continue; + } + @originalEnum.ToString() - first=false; } @@ -102,10 +106,16 @@ - + + @AppLocalization["Group Membership Changes"] + @foreach (var type in Enum.GetValues(typeof(NotificationType))) { var originalEnum = (NotificationType)type; + if (originalEnum == NotificationType.Unassign || originalEnum == NotificationType.Assign) + { + continue; + } @originalEnum.ToString() diff --git a/BLAZAMGui/UI/Settings/Permissions/EditAccessLevel.razor b/BLAZAMGui/UI/Settings/Permissions/EditAccessLevel.razor index cfe36587f..037cc665d 100644 --- a/BLAZAMGui/UI/Settings/Permissions/EditAccessLevel.razor +++ b/BLAZAMGui/UI/Settings/Permissions/EditAccessLevel.razor @@ -55,7 +55,7 @@ - @name + @AppLocalization[name]- @if (!Self) { @@ -106,7 +106,7 @@ Elevation="0"> - @name Actions + @AppLocalization[name] @AppLocalization["Actions"] @AppLocalization[@action.Name] + + @AppLocalization[@action.Name] + } } } @@ -130,8 +132,8 @@ - + Title=@AppLocalization["Action"] /> + @AppLocalization["Deny"] @@ -140,7 +142,7 @@ - + - @name Fields + @AppLocalization[name] @AppLocalization["Fields"] @AppLocalization[field.DisplayName] + + @AppLocalization[field.DisplayName] + } @@ -187,39 +191,41 @@ - + @if (context.Item?.Field != null) { - - @context.Item.Field.DisplayName + + @AppLocalization[context.Item.Field.DisplayName] } else if (context.Item?.CustomField != null) { - @context.Item.CustomField.DisplayName + @AppLocalization[context.Item.CustomField.DisplayName] } - + @foreach (FieldAccessLevel levelValue in FieldAccessLevels.Levels) { - @AppLocalization[levelValue.Name] + + @AppLocalization[levelValue.Name] + } - + diff --git a/BLAZAMGui/UI/Settings/Permissions/ImpersonateUser.razor b/BLAZAMGui/UI/Settings/Permissions/ImpersonateUser.razor index 203dc5b12..5ea1fd4dd 100644 --- a/BLAZAMGui/UI/Settings/Permissions/ImpersonateUser.razor +++ b/BLAZAMGui/UI/Settings/Permissions/ImpersonateUser.razor @@ -17,7 +17,7 @@ - Impersonate User + @AppLocalization["Impersonate User"] diff --git a/BLAZAMGui/UI/Users/ChangeUserPasswordModalContent.razor b/BLAZAMGui/UI/Users/ChangeUserPasswordModalContent.razor index eb556ee73..033b2103f 100644 --- a/BLAZAMGui/UI/Users/ChangeUserPasswordModalContent.razor +++ b/BLAZAMGui/UI/Users/ChangeUserPasswordModalContent.razor @@ -63,7 +63,7 @@ } SnackBarService.Success("Changed password for " + User.DisplayName); await AuditLogger.User.PasswordChanged(User, requireChangeSwitch.Value); - _ = OUNotificationService.PostAsync(User, NotificationType.PasswordChange, CurrentUser.State); + await OUNotificationService.PostAsync(User, NotificationType.PasswordChange, CurrentUser.State); await InvokeAsync(Close); diff --git a/BLAZAMGui/UI/Users/NewTemplateUser.razor b/BLAZAMGui/UI/Users/NewTemplateUser.razor index 2c2477f46..25df5aa99 100644 --- a/BLAZAMGui/UI/Users/NewTemplateUser.razor +++ b/BLAZAMGui/UI/Users/NewTemplateUser.razor @@ -334,7 +334,9 @@ Next + OnClick="@(()=>{OnValidSubmit.InvokeAsync();})"> + @AppLocalization["Next"] + diff --git a/BLAZAMGui/UI/Users/NewUserNameEntry.razor b/BLAZAMGui/UI/Users/NewUserNameEntry.razor index 5c0709e3b..d30be91fd 100644 --- a/BLAZAMGui/UI/Users/NewUserNameEntry.razor +++ b/BLAZAMGui/UI/Users/NewUserNameEntry.razor @@ -25,10 +25,14 @@ Back + OnClick="OnBack"> + @AppLocalization["Back"] + Next + Disabled=@(newUserName is null || (newUserName.Surname.IsNullOrEmpty() && newUserName.GivenName.IsNullOrEmpty()))> + @AppLocalization["Next"] + @code { diff --git a/BLAZAMLocalization/Blazam Translation.xlsx b/BLAZAMLocalization/Blazam Translation.xlsx new file mode 100644 index 000000000..9546c3ab7 Binary files /dev/null and b/BLAZAMLocalization/Blazam Translation.xlsx differ diff --git a/BLAZAMNotifications/Notifications/NotificationTypeExtentions.cs b/BLAZAMNotifications/Notifications/NotificationTypeExtentions.cs index b0680c9ad..37939849a 100644 --- a/BLAZAMNotifications/Notifications/NotificationTypeExtentions.cs +++ b/BLAZAMNotifications/Notifications/NotificationTypeExtentions.cs @@ -21,8 +21,11 @@ public static class NotificationTypeExtentions case NotificationType.Modify: notificationTemplate = new EntryEditedEmailMessage(); break; - case NotificationType.GroupAssignment: - notificationTemplate = new EntryGroupAssignmentEmailMessage(); + case NotificationType.Unassign: + notificationTemplate = new EntryUnassignedEmailMessage(); + break; + case NotificationType.Assign: + notificationTemplate = new EntryAssignedEmailMessage(); break; } diff --git a/BLAZAMServices/Background/NotificationGenerationService.cs b/BLAZAMServices/Background/NotificationGenerationService.cs index 1f080492f..c51881811 100644 --- a/BLAZAMServices/Background/NotificationGenerationService.cs +++ b/BLAZAMServices/Background/NotificationGenerationService.cs @@ -1,5 +1,7 @@ using AngleSharp.Dom; using BLAZAM.ActiveDirectory.Interfaces; +using BLAZAM.Common.Data; +using BLAZAM.Common.Data.Database; using BLAZAM.Database.Context; using BLAZAM.Database.Models.Notifications; using BLAZAM.Database.Models.Permissions; @@ -55,56 +57,84 @@ await Task.Run(async () => PackageNotification(source, notificationType, actor, target, out notification, out notificationTitle, out emailMessage); var _emailConfigured = _emailService.IsConfigured; var users = Context.UserSettings.Include(us => us.NotificationSubscriptions).ToList(); + if (_databaseFactory.DatabaseType == DatabaseType.SQLite) + { + - Parallel.ForEach(users, async user => + foreach (var user in users) + { + await ProcessUserNotification(source, notificationType, actor, user, notification, notificationTitle, emailMessage, _emailConfigured); + } + } + else { - //Avoid sending to triggering user if actor is set - if (user.Id != actor?.Id) + Parallel.ForEach(users, async user => { - var effectiveInAppSubscriptions = CalculateEffectiveInAppSubscriptions(user, source); - var effectiveEmailSubscriptions = CalculateEffectiveEmailSubscriptions(user, source); + await ProcessUserNotification(source, notificationType, actor, user, notification, notificationTitle, emailMessage, _emailConfigured); + }); + } + PostWebHooks(source, notificationType, actor, target); - if (effectiveInAppSubscriptions.NotificationTypes.Any(x => x.NotificationType == notificationType)) - { - await _notificationPublisher.PublishNotification(user, notification); - } + }); - if (effectiveEmailSubscriptions.NotificationTypes.Any(x => x.NotificationType == notificationType)) + } + + private async Task ProcessUserNotification(IDirectoryEntryAdapter source, NotificationType notificationType, IApplicationUserState? actor, AppUser user, NotificationMessage notification, string notificationTitle, NotificationTemplateComponent? emailMessage, bool _emailConfigured) + { + //Avoid sending to triggering user if actor is set + if (user.Id != actor?.Id) + { + var effectiveInAppSubscriptions = CalculateEffectiveInAppSubscriptions(user, source); + var effectiveEmailSubscriptions = CalculateEffectiveEmailSubscriptions(user, source); + + if (effectiveInAppSubscriptions.NotificationTypes.Any(x => x.NotificationType == notificationType)) + { + await _notificationPublisher.PublishNotification(user, notification); + } + + if (effectiveEmailSubscriptions.NotificationTypes.Any(x => x.NotificationType == notificationType)) + { + if (emailMessage != null) + { + if (_emailConfigured && !user.Email.IsNullOrEmpty()) { - 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); - } + await _emailService.SendMessage(notificationTitle, emailMessage, user.Email); } } - }); - PostWebHooks(source, notificationType, actor , target ); - - }); - + else + { + var error = new ApplicationException(); + Loggers.SystemLogger.Error("Email message template was not found! {@Error}", error); + } + } + } } + private async Task PostWebHooks(IDirectoryEntryAdapter source, NotificationType notificationType, IApplicationUserState? actor = null, IDirectoryEntryAdapter? target = null) { var webhooks = await Context.WebHookSubscriptions.Where(w => w.DeletedAt == null) - .Include(w=>w.NotificationTypes) + .Include(w => w.NotificationTypes) .Where(x => x.DeletedAt == null) .ToListAsync(); if (webhooks.Any(w => w.NotificationTypes.Any(nt => nt.NotificationType == notificationType))) { var subscribedWebhooks = webhooks.Where(w => w.NotificationTypes.Any(nt => nt.NotificationType == notificationType)); - Parallel.ForEach(subscribedWebhooks, async webhook => { - _webHookPublisher.PublishWebhook(webhook, source, notificationType,actor, target); - }); + if (_databaseFactory.DatabaseType == DatabaseType.SQLite) + { + foreach(var webhook in subscribedWebhooks) + { + _webHookPublisher.PublishWebhook(webhook, source, notificationType, actor, target); + } + } + else + { + Parallel.ForEach(subscribedWebhooks, async webhook => + { + _webHookPublisher.PublishWebhook(webhook, source, notificationType, actor, target); + }); + } + - } } /// @@ -154,15 +184,25 @@ public void PackageNotification(IDirectoryEntryAdapter source, NotificationType editedMessage.EntryName = source.CanonicalName; emailMessage = editedMessage; break; - case NotificationType.GroupAssignment: + case NotificationType.Unassign: + notification.Action = ActiveDirectoryObjectAction.Unassign; + + notificationTitle += _appLocalization["Removed from Group"]; + notificationBody += _appLocalization["was removed from"] + " " + target.CanonicalName + " " + _appLocalization[" at "] + time; + + var groupMemberRemovedMessage = NotificationType.Unassign.ToNotification(); + groupMemberRemovedMessage.EntryName = source.CanonicalName; + emailMessage = groupMemberRemovedMessage; + break; + case NotificationType.Assign: notification.Action = ActiveDirectoryObjectAction.Assign; - notificationTitle += _appLocalization["Group Membership Changed"]; - notificationBody += _appLocalization["was assigned/removed from "] + "" + target.CanonicalName + " " + _appLocalization[" at "] + time; + notificationTitle += _appLocalization["Added to Group"]; + notificationBody += _appLocalization["was assigned to"] + " " + target.CanonicalName + " " + _appLocalization[" at "] + time; - var groupMembershipMessage = NotificationType.GroupAssignment.ToNotification(); - groupMembershipMessage.EntryName = source.CanonicalName; - emailMessage = groupMembershipMessage; + var groupMemberAssignedMessage = NotificationType.Assign.ToNotification(); + groupMemberAssignedMessage.EntryName = source.CanonicalName; + emailMessage = groupMemberAssignedMessage; break; case NotificationType.PasswordChange: notification.Action = ActiveDirectoryObjectAction.SetPassword; diff --git a/BLAZAMServices/WebHookPublisher.cs b/BLAZAMServices/WebHookPublisher.cs index 040680838..7719de5a1 100644 --- a/BLAZAMServices/WebHookPublisher.cs +++ b/BLAZAMServices/WebHookPublisher.cs @@ -23,6 +23,7 @@ using System.Security.Authentication; using Azure; using Polly; +using BLAZAM.Common.Data.Database; namespace BLAZAM.Notifications.Services @@ -65,13 +66,27 @@ private async Task Run() .Where(w => w.Delivered == false && w.RetryCount < 15) .ToList(); - Parallel.ForEachAsync(undeliveredWebhooks, async (attempt, cancel) => + if (_appDatabaseFactory.DatabaseType == DatabaseType.SQLite) + { + foreach(var attempt in undeliveredWebhooks) + { + var attemptId = Guid.NewGuid(); + + await SendWebHook(attempt.WebHookSubscription, attempt.MessageGuid, attemptId, attempt.EventTimestamp, attempt.Body, attempt.EventType, attempt.Signature); + } + } + else + { + + + Parallel.ForEachAsync(undeliveredWebhooks, async (attempt, cancel) => { var attemptId = Guid.NewGuid(); - await SendWebHook(attempt.WebHookSubscription, attempt.MessageGuid, attemptId, attempt.EventTimestamp, attempt.Body, attempt.EventType ,attempt.Signature); + await SendWebHook(attempt.WebHookSubscription, attempt.MessageGuid, attemptId, attempt.EventTimestamp, attempt.Body, attempt.EventType, attempt.Signature); }); + } } catch (Exception ex) { @@ -127,7 +142,7 @@ public async Task PublishWebhook(WebHookSubscription subscription, var payloadString = System.Text.Json.JsonSerializer.Serialize(payload); if (subscription.WebHookSignature == WebHookSignature.HMAC) { - if (subscription.HmacKey.IsNullOrEmpty()) + if (subscription.HmacKey.IsNullOrEmpty()) throw new ApplicationException("HMAC Key not supplied to subscription set to use it."); var key = subscription.HmacKey.Decrypt(); if (key.StartsWith(prefix)) @@ -158,7 +173,7 @@ private async Task SendWebHook(WebHookSubscription subscription, Guid msgId, Gui Method = subscription.WebHookMethod == WebHookMethod.GET ? HttpMethod.Get : HttpMethod.Post, Content = new StringContent(payloadString, Encoding.UTF8, "application/json") - }; + }; request.Headers.Add(UNBRANDED_ID_HEADER_KEY, msgId.ToString()); request.Headers.Add(UNBRANDED_ATTEMPT_ID_HEADER_KEY, attemptId.ToString()); @@ -189,7 +204,7 @@ private async Task SendWebHook(WebHookSubscription subscription, Guid msgId, Gui { Body = payloadString, MessageGuid = msgId, - EventType= eventType, + EventType = eventType, Uri = request.RequestUri.ToString(), Delivered = false, WebHookSubscriptionId = subscription.Id, diff --git a/BLAZAMThemes/ApplicationTheme.cs b/BLAZAMThemes/ApplicationTheme.cs index b7a43f3ed..c7289f190 100644 --- a/BLAZAMThemes/ApplicationTheme.cs +++ b/BLAZAMThemes/ApplicationTheme.cs @@ -25,7 +25,7 @@ public ApplicationTheme() DrawerText = System.Drawing.Color.WhiteSmoke.ToHex(), Background = "#efefef", //Info = "#46a9ef", - //Success = System.Drawing.Color.ForestGreen.ToHex(), + Success = "#00c853", //Warning = "#ff9900", //Error = System.Drawing.Color.Red.ToHex(), TextDisabled = System.Drawing.Color.DarkGray.ToHex(), @@ -40,7 +40,7 @@ public ApplicationTheme() Background = "#383b40", DrawerText = "#c7c7c7", //Info = "#1b8f7e", - //Success = "#5fad00", + Success = "#00c853", //Warning = "#ffc270", //Error = "#f60066", TextDisabled = System.Drawing.Color.DarkGray.ToHex(), diff --git a/BLAZAMUpdate/BLAZAMUpdate.csproj b/BLAZAMUpdate/BLAZAMUpdate.csproj index 22b60fb8e..5a9a030f0 100644 --- a/BLAZAMUpdate/BLAZAMUpdate.csproj +++ b/BLAZAMUpdate/BLAZAMUpdate.csproj @@ -8,7 +8,7 @@ - + diff --git a/README.md b/README.md index a7bcfe1d2..b837cbb68 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # BLAZAM Proudly serving -![image](https://github.com/user-attachments/assets/0c5e2de1-2174-4238-a944-8e9cc4b8cd4a) +![image](https://github.com/user-attachments/assets/32c47f17-cd57-47a1-b029-b3c19900d429) ## Version 1.0.0 Release Notice