diff --git a/Oqtane.Client/Modules/Admin/Files/Add.razor b/Oqtane.Client/Modules/Admin/Files/Add.razor index fca41914..26feaf57 100644 --- a/Oqtane.Client/Modules/Admin/Files/Add.razor +++ b/Oqtane.Client/Modules/Admin/Files/Add.razor @@ -33,15 +33,18 @@ string result = await FileService.UploadFilesAsync(PageState.Site.SiteRootPath, files, ""); if (result == "") { + await logger.LogInformation("Files Uploaded Successfully"); AddModuleMessage("Files Uploaded Successfully", MessageType.Success); } else { + await logger.LogError("Upload Failed For {Files}", result.Replace(",",", ")); AddModuleMessage("Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error); } } catch (Exception ex) { + await logger.LogError(ex, "Upload Failed {Error}", ex.Message); AddModuleMessage("Upload Failed. " + ex.Message, MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Files/Index.razor b/Oqtane.Client/Modules/Admin/Files/Index.razor index b73936b8..18d8b7d4 100644 --- a/Oqtane.Client/Modules/Admin/Files/Index.razor +++ b/Oqtane.Client/Modules/Admin/Files/Index.razor @@ -33,14 +33,31 @@ else protected override async Task OnParametersSetAsync() { - Files = await FileService.GetFilesAsync(PageState.Site.SiteRootPath); - uri = new Uri(NavigationManager.Uri); + try + { + Files = await FileService.GetFilesAsync(PageState.Site.SiteRootPath); + uri = new Uri(NavigationManager.Uri); + } + catch (Exception ex) + { + await logger.LogError("Error Loading Files {Error}", ex.Message); + AddModuleMessage("Error Loading Files", MessageType.Error); + } } private async Task DeleteFile(string filename) { - await FileService.DeleteFileAsync(PageState.Site.SiteRootPath, filename); - Files = await FileService.GetFilesAsync(PageState.Site.SiteRootPath); - AddModuleMessage("File Deleted", MessageType.Success); + try + { + await FileService.DeleteFileAsync(PageState.Site.SiteRootPath, filename); + Files = await FileService.GetFilesAsync(PageState.Site.SiteRootPath); + await logger.LogInformation("File Deleted"); + AddModuleMessage("File Deleted", MessageType.Success); + } + catch (Exception ex) + { + await logger.LogError("Error Deleting File {Error}", ex.Message); + AddModuleMessage("Error Deleting File", MessageType.Error); + } } } \ No newline at end of file diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index 411c0d8d..bd0c871a 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -64,6 +64,7 @@ } else { + await logger.LogInformation("Login Failed For Username {Username}", Username); AddModuleMessage("Login Failed. Please Remember That Passwords Are Case Sensitive.", MessageType.Error); } } @@ -82,6 +83,7 @@ } else { + await logger.LogInformation("Login Failed For Username {Username}", Username); AddModuleMessage("Login Failed. Please Remember That Passwords Are Case Sensitive.", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Logs/Index.razor b/Oqtane.Client/Modules/Admin/Logs/Index.razor new file mode 100644 index 00000000..c564d23e --- /dev/null +++ b/Oqtane.Client/Modules/Admin/Logs/Index.razor @@ -0,0 +1,38 @@ +@namespace Oqtane.Modules.Admin.Logs +@inherits ModuleBase +@inject ILogService LogService + +@if (Logs == null) +{ +

Loading...

+} +else +{ + +
+ Date + Level + Url + Category + Message +
+ + @context.LogDate + @context.Level + @context.Url + @context.Category + @context.Message + +
+} + +@code { + public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } } + + List Logs; + + protected override async Task OnInitializedAsync() + { + Logs = await LogService.GetLogsAsync(PageState.Site.SiteId); + } +} \ No newline at end of file diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor index 810ae6c7..e234650f 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor @@ -54,15 +54,23 @@ protected override async Task OnInitializedAsync() { - List moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); - packages = await PackageService.GetPackagesAsync("module"); - foreach(Package package in packages.ToArray()) + try { - if (moduledefinitions.Exists(item => Utilities.GetTypeName(item.ModuleDefinitionName) == package.PackageId)) + List moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); + packages = await PackageService.GetPackagesAsync("module"); + foreach(Package package in packages.ToArray()) { - packages.Remove(package); + if (moduledefinitions.Exists(item => Utilities.GetTypeName(item.ModuleDefinitionName) == package.PackageId)) + { + packages.Remove(package); + } } } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Packages {Error}", ex.Message); + AddModuleMessage("Error Loading Packages", MessageType.Error); + } } private async Task UploadFile() @@ -77,22 +85,26 @@ string result = await FileService.UploadFilesAsync("Modules", files, ""); if (result == "") { + await logger.LogInformation("Module Uploaded Successfully {Package}", files[0]); AddModuleMessage("Module Uploaded Successfully. Click Install To Complete Installation.", MessageType.Success); uploaded = true; StateHasChanged(); } else { - AddModuleMessage("Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error); + await logger.LogError("Module Upload Failed For {Package}", files[0]); + AddModuleMessage("Module Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error); } } catch (Exception ex) { - AddModuleMessage("Module Upload Failed. " + ex.Message, MessageType.Error); + await logger.LogError(ex, "Module Upload Failed For {Package} {Error}", files[0], ex.Message); + AddModuleMessage("Module Upload Failed.", MessageType.Error); } } else { + await logger.LogError("Invalid Module Package {Package}", files[0]); AddModuleMessage("Invalid Module Package", MessageType.Error); } } @@ -104,15 +116,31 @@ private async Task InstallModules() { - await ModuleDefinitionService.InstallModuleDefinitionsAsync(); - NavigationManager.NavigateTo(NavigateUrl(Reload.Application)); + try + { + await ModuleDefinitionService.InstallModuleDefinitionsAsync(); + NavigationManager.NavigateTo(NavigateUrl(Reload.Application)); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Installating Module"); + } } private async Task DownloadModule(string moduledefinitionname, string version) { - await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules"); - AddModuleMessage("Module Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success); - uploaded = true; - StateHasChanged(); + try + { + await PackageService.DownloadPackageAsync(moduledefinitionname, version, "Modules"); + await logger.LogInformation("Module {ModuleDefinitionName} {Version} Downloaded Successfully", moduledefinitionname, version); + AddModuleMessage("Module Downloaded Successfully. Click Install To Complete Installation.", MessageType.Success); + uploaded = true; + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version}", moduledefinitionname, version); + AddModuleMessage("Error Downloading Module", MessageType.Error); + } } } diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor index 2f2a2a85..21d90d91 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor @@ -40,7 +40,7 @@ PermissionGrid permissiongrid; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { try { @@ -58,7 +58,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading ModuleDefinition {ModuleDefinitionId} {Error}", ModuleDefinitionId, ex.Message); + AddModuleMessage("Error Loading Module", MessageType.Error); } } @@ -69,11 +70,13 @@ ModuleDefinition moduledefinition = PageState.ModuleDefinitions.Where(item => item.ModuleDefinitionId == ModuleDefinitionId).FirstOrDefault(); moduledefinition.Permissions = permissiongrid.GetPermissions(); await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition); + await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition); NavigationManager.NavigateTo(NavigateUrl(Reload.Site)); } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving ModuleDefinition {ModuleDefinitionId} {Error}", ModuleDefinitionId, ex.Message); + AddModuleMessage("Error Saving Module", MessageType.Error); } } } diff --git a/Oqtane.Client/Modules/Admin/Modules/Import.razor b/Oqtane.Client/Modules/Admin/Modules/Import.razor index abcaff32..2db62162 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Import.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Import.razor @@ -30,8 +30,16 @@ { if (content != "") { - await ModuleService.ImportModuleAsync(ModuleState.ModuleId, content); - NavigationManager.NavigateTo(NavigateUrl(Reload.Page)); + try + { + await ModuleService.ImportModuleAsync(ModuleState.ModuleId, content); + NavigationManager.NavigateTo(NavigateUrl(Reload.Page)); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Importing Module {ModuleId} {Error}", ModuleState.ModuleId, ex.Message); + AddModuleMessage("Error Importing Module", MessageType.Error); + } } else { diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index a7caf311..733a9b3a 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -153,7 +153,7 @@ PermissionGrid permissiongrid; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { try { @@ -173,11 +173,12 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message); + AddModuleMessage("Error Initializing Page", MessageType.Error); } } - private void ParentChanged(ChangeEventArgs e) + private async void ParentChanged(ChangeEventArgs e) { try { @@ -194,11 +195,12 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", parentid, ex.Message); + AddModuleMessage("Error Loading Child Pages For Parent", MessageType.Error); } } - private void ThemeChanged(ChangeEventArgs e) + private async void ThemeChanged(ChangeEventArgs e) { try { @@ -215,17 +217,19 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", themetype, ex.Message); + AddModuleMessage("Error Loading Pane Layouts For Theme", MessageType.Error); } } private async Task SavePage() { + Page page = null; try { if (name != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype))) { - Page page = new Page(); + page = new Page(); page.SiteId = PageState.Page.SiteId; page.Name = name; if (path == "") @@ -291,6 +295,7 @@ await PageService.AddPageAsync(page); await PageService.UpdatePageOrderAsync(page.SiteId, page.ParentId); + await logger.LogInformation("Page Added {Page}", page); NavigationManager.NavigateTo(NavigateUrl(page.Path, Reload.Site)); } else @@ -301,7 +306,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving Page {Page} {Error}", page, ex.Message); + AddModuleMessage("Error Saving Page", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Delete.razor b/Oqtane.Client/Modules/Admin/Pages/Delete.razor index 82c0db0d..b156b922 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Delete.razor @@ -130,7 +130,7 @@ string deletedby; DateTime? deletedon; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { try { @@ -159,7 +159,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Page {PageId} {Error}", PageId, ex.Message); + AddModuleMessage("Error Loading Page", MessageType.Error); } } @@ -167,12 +168,14 @@ { try { - await PageService.DeletePageAsync(Int32.Parse(PageState.QueryString["id"])); - NavigationManager.NavigateTo(NavigateUrl("", Reload.Site)); + await PageService.DeletePageAsync(PageId); + await logger.LogInformation("Page Deleted {PageId}", PageId); + NavigationManager.NavigateTo(NavigateUrl("", Reload.Site)); // redirect to home page } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Deleting Page {PageId} {Error}", PageId, ex.Message); + AddModuleMessage("Error Deleting Page", MessageType.Error); } } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 0cfb461d..3f932150 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -182,7 +182,7 @@ PermissionGrid permissiongrid; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { try { @@ -227,11 +227,12 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Page {PageId} {Error}", PageId, ex.Message); + AddModuleMessage("Error Loading Page", MessageType.Error); } } - private void ParentChanged(ChangeEventArgs e) + private async void ParentChanged(ChangeEventArgs e) { try { @@ -256,11 +257,12 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", parentid, ex.Message); + AddModuleMessage("Error Loading Child Pages For Parent", MessageType.Error); } } - private void ThemeChanged(ChangeEventArgs e) + private async void ThemeChanged(ChangeEventArgs e) { try { @@ -277,17 +279,19 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", themetype, ex.Message); + AddModuleMessage("Error Loading Pane Layouts For Theme", MessageType.Error); } } private async Task SavePage() { + Page page = null; try { if (name != "" && !string.IsNullOrEmpty(themetype) && (panelayouts.Count == 0 || !string.IsNullOrEmpty(layouttype))) { - Page page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault(); + page = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault(); string currentpath = page.Path; page.Name = name; @@ -375,6 +379,7 @@ } } + await logger.LogInformation("Page Saved {Page}", page); NavigationManager.NavigateTo(NavigateUrl(page.Path, Reload.Site)); } else @@ -384,7 +389,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving Page {Page} {Error}", page, ex.Message); + AddModuleMessage("Error Saving Page", MessageType.Error); } } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Index.razor b/Oqtane.Client/Modules/Admin/Pages/Index.razor index d92b1b14..47e96364 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Index.razor @@ -34,7 +34,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Pages {Error}", ex.Message); + AddModuleMessage("Error Loading Pages", MessageType.Error); } } } diff --git a/Oqtane.Client/Modules/Admin/Profile/Index.razor b/Oqtane.Client/Modules/Admin/Profile/Index.razor index 4e87f52e..4760a4f4 100644 --- a/Oqtane.Client/Modules/Admin/Profile/Index.razor +++ b/Oqtane.Client/Modules/Admin/Profile/Index.razor @@ -99,7 +99,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message); + AddModuleMessage("Error Loading User Profile", MessageType.Error); } } @@ -119,12 +120,14 @@ user.DisplayName = displayname; await UserService.UpdateUserAsync(user); await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); + await logger.LogInformation("User Profile Saved"); NavigationManager.NavigateTo(NavigateUrl("")); } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving User Profile {Error}", ex.Message); + AddModuleMessage("Error Saving User Profile", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Register/Index.razor b/Oqtane.Client/Modules/Admin/Register/Index.razor index af68c17d..96f56640 100644 --- a/Oqtane.Client/Modules/Admin/Register/Index.razor +++ b/Oqtane.Client/Modules/Admin/Register/Index.razor @@ -43,10 +43,12 @@ if (user != null) { + await logger.LogInformation("User Created {Username} {Email}", Username, Email); NavigationManager.NavigateTo(NavigateUrl("")); } else { + await logger.LogError("Error Adding User {Username} {Email}", Username, Email); AddModuleMessage("Error Adding User. Please Ensure Password Meets Complexity Requirements And Username Is Not Already In Use.", MessageType.Error); } } @@ -57,7 +59,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", Username, Email, ex.Message); + AddModuleMessage("Error Adding User", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Roles/Add.razor b/Oqtane.Client/Modules/Admin/Roles/Add.razor index f7b35408..8317cdf7 100644 --- a/Oqtane.Client/Modules/Admin/Roles/Add.razor +++ b/Oqtane.Client/Modules/Admin/Roles/Add.razor @@ -64,12 +64,14 @@ role.Description = description; role.IsAutoAssigned = (isautoassigned == null ? false : Boolean.Parse(isautoassigned)); role.IsSystem = (issystem == null ? false : Boolean.Parse(issystem)); - await RoleService.AddRoleAsync(role); + role = await RoleService.AddRoleAsync(role); + await logger.LogInformation("Role Added {Role}", role); NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { + await logger.LogError(ex, "Error Adding Role", ex.Message); AddModuleMessage(ex.Message, MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Roles/Delete.razor b/Oqtane.Client/Modules/Admin/Roles/Delete.razor index efb6b38b..b7210c7d 100644 --- a/Oqtane.Client/Modules/Admin/Roles/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Roles/Delete.razor @@ -71,7 +71,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Role {RoleId} {Error}", roleid, ex.Message); + AddModuleMessage("Error Loading Role", MessageType.Error); } } @@ -80,11 +81,13 @@ try { await RoleService.DeleteRoleAsync(roleid); + await logger.LogInformation("Role Deleted {RoleId}", roleid); NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Deleting Role {RoleId} {Error}", roleid, ex.Message); + AddModuleMessage("Error Deleting Role", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Roles/Edit.razor b/Oqtane.Client/Modules/Admin/Roles/Edit.razor index 91d0e4d7..acc8c888 100644 --- a/Oqtane.Client/Modules/Admin/Roles/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Roles/Edit.razor @@ -71,7 +71,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Role {RoleId} {Error}", roleid, ex.Message); + AddModuleMessage("Error Loading Role", MessageType.Error); } } @@ -80,20 +81,18 @@ try { Role role = await RoleService.GetRoleAsync(roleid); - if (role != null) - { - role.Name = name; - role.Description = description; - role.IsAutoAssigned = (isautoassigned == null ? false : Boolean.Parse(isautoassigned)); - role.IsSystem = (issystem == null ? false : Boolean.Parse(issystem)); - await RoleService.UpdateRoleAsync(role); - } + role.Name = name; + role.Description = description; + role.IsAutoAssigned = (isautoassigned == null ? false : Boolean.Parse(isautoassigned)); + role.IsSystem = (issystem == null ? false : Boolean.Parse(issystem)); + role = await RoleService.UpdateRoleAsync(role); + await logger.LogInformation("Role Saved {Role}", role); NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving Role {RoleId} {Error}", roleid, ex.Message); + AddModuleMessage("Error Saving Role", MessageType.Error); } } - } diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index 56afd460..66a7d303 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -146,7 +146,7 @@ else username = PageState.User.Username; } - private void TenantChanged(ChangeEventArgs e) + private async void TenantChanged(ChangeEventArgs e) { try { @@ -163,11 +163,12 @@ else } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", tenantid, ex.Message); + AddModuleMessage("Error Loading Tenant", MessageType.Error); } } - private void ThemeChanged(ChangeEventArgs e) + private async void ThemeChanged(ChangeEventArgs e) { try { @@ -184,7 +185,8 @@ else } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", themetype, ex.Message); + AddModuleMessage("Error Loading Pane Layouts For Theme", MessageType.Error); } } @@ -250,12 +252,14 @@ else await TenantService.UpdateTenantAsync(tenant); } } + await logger.LogInformation("Site Created {Site}", site); Uri uri = new Uri(NavigationManager.Uri); NavigationManager.NavigateTo(uri.Scheme + "://" + aliases[0].Name, true); } else { + await logger.LogError("Invalid Password Entered For Host {Username}", username); AddModuleMessage("Invalid Host Password", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Sites/Delete.razor b/Oqtane.Client/Modules/Admin/Sites/Delete.razor index ac695c65..e3edec7a 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Delete.razor @@ -163,7 +163,8 @@ else } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", siteid, ex.Message); + AddModuleMessage("Error Loading Site", MessageType.Error); } } @@ -172,10 +173,12 @@ else try { await SiteService.DeleteSiteAsync(siteid, Alias); + await logger.LogInformation("Sited Deleted {SiteId}", siteid); NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { + await logger.LogError(ex, "Error Deleting Site {Error}", ex.Message); AddModuleMessage(ex.Message, MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Sites/Edit.razor b/Oqtane.Client/Modules/Admin/Sites/Edit.razor index 47ec5e67..b870e57d 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Edit.razor @@ -164,11 +164,12 @@ else } catch (Exception ex) { + await logger.LogError(ex, "Error Loading Site {SiteId} {Error}", siteid, ex.Message); AddModuleMessage(ex.Message, MessageType.Error); } } - private void ThemeChanged(ChangeEventArgs e) + private async void ThemeChanged(ChangeEventArgs e) { try { @@ -185,7 +186,8 @@ else } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", themetype, ex.Message); + AddModuleMessage("Error Loading Pane Layouts For Theme", MessageType.Error); } } @@ -227,6 +229,7 @@ else await AliasService.AddAliasAsync(alias); } } + await logger.LogInformation("Site Saved {Site}", site); NavigationManager.NavigateTo(NavigateUrl(Reload.Site)); } @@ -238,7 +241,8 @@ else } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving Site {SiteId} {Error}", siteid, ex.Message); + AddModuleMessage("Error Saving Site", MessageType.Error); } } } diff --git a/Oqtane.Client/Modules/Admin/Tenants/Add.razor b/Oqtane.Client/Modules/Admin/Tenants/Add.razor index 9588407d..e12a27a3 100644 --- a/Oqtane.Client/Modules/Admin/Tenants/Add.razor +++ b/Oqtane.Client/Modules/Admin/Tenants/Add.razor @@ -50,7 +50,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message); + AddModuleMessage("Error Loading Tenants", MessageType.Error); } } @@ -68,11 +69,13 @@ tenant.DBSchema = schema; tenant.IsInitialized = false; await TenantService.AddTenantAsync(tenant); + await logger.LogInformation("Tenant Created {Tenant}", tenant); NavigationManager.NavigateTo(NavigateUrl()); } else { + await logger.LogError("Error Creating Tenant {Error}", response.Message); AddModuleMessage(response.Message, MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Tenants/Delete.razor b/Oqtane.Client/Modules/Admin/Tenants/Delete.razor index 4cdb5f5d..7220c38f 100644 --- a/Oqtane.Client/Modules/Admin/Tenants/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Tenants/Delete.razor @@ -55,16 +55,26 @@ } catch (Exception ex) { + await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", tenantid, ex.Message); AddModuleMessage(ex.Message, MessageType.Error); } } private async Task DeleteTenant() { - Tenant tenant = await TenantService.GetTenantAsync(tenantid); - if (tenant != null) + try { - await TenantService.DeleteTenantAsync(tenantid); + Tenant tenant = await TenantService.GetTenantAsync(tenantid); + if (tenant != null) + { + await TenantService.DeleteTenantAsync(tenantid); + await logger.LogInformation("Tenant Deleted {TenantId}", tenantid); + NavigationManager.NavigateTo(NavigateUrl()); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Deleting Tenant {TenantId} {Error}", tenantid, ex.Message); + AddModuleMessage("Error Deleting Tenant", MessageType.Error); } - NavigationManager.NavigateTo(NavigateUrl()); } } diff --git a/Oqtane.Client/Modules/Admin/Tenants/Edit.razor b/Oqtane.Client/Modules/Admin/Tenants/Edit.razor index 365721a2..ca0b8c9c 100644 --- a/Oqtane.Client/Modules/Admin/Tenants/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Tenants/Edit.razor @@ -55,21 +55,32 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", tenantid, ex.Message); + AddModuleMessage("Error Loading Tenant", MessageType.Error); } } private async Task SaveTenant() { - connectionstring = connectionstring.Replace("\\\\", "\\"); - Tenant tenant = await TenantService.GetTenantAsync(tenantid); - if (tenant != null) + try { - tenant.Name = name; - tenant.DBConnectionString = connectionstring; - tenant.DBSchema = schema; - await TenantService.UpdateTenantAsync(tenant); + connectionstring = connectionstring.Replace("\\\\", "\\"); + Tenant tenant = await TenantService.GetTenantAsync(tenantid); + if (tenant != null) + { + tenant.Name = name; + tenant.DBConnectionString = connectionstring; + tenant.DBSchema = schema; + await TenantService.UpdateTenantAsync(tenant); + await logger.LogInformation("Tenant Saved {TenantId}", tenantid); + + NavigationManager.NavigateTo(NavigateUrl()); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Saving Tenant {TenantId} {Error}", tenantid, ex.Message); + AddModuleMessage("Error Saving Tenant", MessageType.Error); } - NavigationManager.NavigateTo(NavigateUrl()); } } diff --git a/Oqtane.Client/Modules/Admin/Themes/Add.razor b/Oqtane.Client/Modules/Admin/Themes/Add.razor index aad68ca5..bd243c9e 100644 --- a/Oqtane.Client/Modules/Admin/Themes/Add.razor +++ b/Oqtane.Client/Modules/Admin/Themes/Add.razor @@ -76,22 +76,26 @@ string result = await FileService.UploadFilesAsync("Themes", files, ""); if (result == "") { + await logger.LogInformation("Theme Uploaded {Package}", files[0]); AddModuleMessage("Theme Uploaded Successfully. Click Install To Complete Installation.", MessageType.Success); uploaded = true; StateHasChanged(); } else { + await logger.LogInformation("Theme Upload Failed For {Package}", result.Replace(",",", ")); AddModuleMessage("Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error); } } catch (Exception ex) { - AddModuleMessage("Theme Upload Failed. " + ex.Message, MessageType.Error); + await logger.LogError(ex, "Theme Upload Failed {Package} {Error}", files[0], ex.Message); + AddModuleMessage("Theme Upload Failed", MessageType.Error); } } else { + await logger.LogError("Invalid Theme Package {Package}", files[0]); AddModuleMessage("Invalid Theme Package", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Upgrade/Index.razor b/Oqtane.Client/Modules/Admin/Upgrade/Index.razor index 827069e2..2ae44820 100644 --- a/Oqtane.Client/Modules/Admin/Upgrade/Index.razor +++ b/Oqtane.Client/Modules/Admin/Upgrade/Index.razor @@ -65,22 +65,26 @@ else string result = await FileService.UploadFilesAsync("Framework", files, ""); if (result == "") { + await logger.LogInformation("Framework Uploaded {Package}", files[0]); AddModuleMessage("Framework Uploaded Successfully. Click Upgrade To Complete Installation.", MessageType.Success); uploaded = true; StateHasChanged(); } else { + await logger.LogInformation("Framework Upload Failed For {Package}", result.Replace(",",", ")); AddModuleMessage("Upload Failed For " + result.Replace(",",", ") + ". This Could Be Due To A Network Error Or Because A File Type Is Restricted.", MessageType.Error); } } catch (Exception ex) { + await logger.LogError(ex, "Framework Upload Failed {Package} {Error}", files[0], ex.Message); AddModuleMessage("Framework Upload Failed. " + ex.Message, MessageType.Error); } } else { + await logger.LogError("Invalid Framework Package {Package}", files[0]); AddModuleMessage("Invalid Framework Package", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Users/Add.razor b/Oqtane.Client/Modules/Admin/Users/Add.razor index b2b4b7df..7d9e6647 100644 --- a/Oqtane.Client/Modules/Admin/Users/Add.razor +++ b/Oqtane.Client/Modules/Admin/Users/Add.razor @@ -87,7 +87,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message); + AddModuleMessage("Error Loading User Profile", MessageType.Error); } } @@ -107,16 +108,19 @@ if (user != null) { await SettingService.UpdateUserSettingsAsync(settings, user.UserId); + await logger.LogInformation("User Created {User}", user); NavigationManager.NavigateTo(NavigateUrl()); } else { + await logger.LogError("Error Adding User {Username} {Email}", username, email); AddModuleMessage("Error Adding User. Please Ensure Password Meets Complexity Requirements And Username Is Not Already In Use.", MessageType.Error); } } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", username, email, ex.Message); + AddModuleMessage("Error Adding User", MessageType.Error); } } @@ -126,4 +130,4 @@ settings = SettingService.SetSetting(settings, SettingName, value); } - } +} diff --git a/Oqtane.Client/Modules/Admin/Users/Delete.razor b/Oqtane.Client/Modules/Admin/Users/Delete.razor index 5219002b..efe7a03c 100644 --- a/Oqtane.Client/Modules/Admin/Users/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Users/Delete.razor @@ -88,7 +88,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message); + AddModuleMessage("Error Loading User", MessageType.Error); } } @@ -100,14 +101,15 @@ if (user != null) { await UserService.DeleteUserAsync(userid); + await logger.LogInformation("User Deleted {UserId}", userid); + NavigationManager.NavigateTo(NavigateUrl()); } - NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { + await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message); AddModuleMessage(ex.Message, MessageType.Error); } } - } diff --git a/Oqtane.Client/Modules/Admin/Users/Edit.razor b/Oqtane.Client/Modules/Admin/Users/Edit.razor index 882f9d10..40a5605d 100644 --- a/Oqtane.Client/Modules/Admin/Users/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Users/Edit.razor @@ -125,7 +125,8 @@ } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message); + AddModuleMessage("Error Loading User", MessageType.Error); } } @@ -148,12 +149,14 @@ user = await UserService.UpdateUserAsync(user); await SettingService.UpdateUserSettingsAsync(settings, user.UserId); + await logger.LogInformation("User Saved {User}", user); NavigationManager.NavigateTo(NavigateUrl()); } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving User {Username} {Email} {Error}", username, email, ex.Message); + AddModuleMessage("Error Saving User", MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/Users/Roles.razor b/Oqtane.Client/Modules/Admin/Users/Roles.razor index cf0a4914..94179f86 100644 --- a/Oqtane.Client/Modules/Admin/Users/Roles.razor +++ b/Oqtane.Client/Modules/Admin/Users/Roles.razor @@ -84,14 +84,23 @@ else } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Loading Roles {Error}", ex.Message); + AddModuleMessage("Error Loading Roles", MessageType.Error); } } private async Task GetUserRoles() { - userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); - userroles = userroles.Where(item => item.UserId == userid).ToList(); + try + { + userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); + userroles = userroles.Where(item => item.UserId == userid).ToList(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading User Roles {UserId} {Error}", userid, ex.Message); + AddModuleMessage("Error Loading User Roles", MessageType.Error); + } } private async Task SaveUserRole() @@ -145,6 +154,7 @@ else await UserRoleService.AddUserRoleAsync(userrole); } await GetUserRoles(); + await logger.LogInformation("User Assigned To Role {UserRole}", userrole); AddModuleMessage("User Assigned To Role", MessageType.Success); } else @@ -154,15 +164,24 @@ else } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving User Roles {UserId} {Error}", userid, ex.Message); + AddModuleMessage("Error Saving User Roles", MessageType.Error); } } private async Task DeleteUserRole(int UserRoleId) { - await UserRoleService.DeleteUserRoleAsync(UserRoleId); - await GetUserRoles(); - AddModuleMessage("User Removed From Role", MessageType.Success); + try + { + await UserRoleService.DeleteUserRoleAsync(UserRoleId); + await GetUserRoles(); + await logger.LogInformation("User Removed From Role {UserRoleId}", UserRoleId); + AddModuleMessage("User Removed From Role", MessageType.Success); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Removing User From Role {UserRoleId} {Error}", UserRoleId, ex.Message); + AddModuleMessage("Error Removing User From Role", MessageType.Error); + } } - } \ No newline at end of file diff --git a/Oqtane.Client/Modules/HtmlText/Edit.razor b/Oqtane.Client/Modules/HtmlText/Edit.razor index e1400d6f..f9d891d4 100644 --- a/Oqtane.Client/Modules/HtmlText/Edit.razor +++ b/Oqtane.Client/Modules/HtmlText/Edit.razor @@ -49,6 +49,7 @@ } catch (Exception ex) { + await logger.LogError(ex, "An Error Occurred Loading Html/Text Content. " + ex.Message); AddModuleMessage(ex.Message, MessageType.Error); } } @@ -71,11 +72,13 @@ htmltext.Content = content; await htmltextservice.AddHtmlTextAsync(htmltext); } + await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext); NavigationManager.NavigateTo(NavigateUrl(Reload.Page)); } catch (Exception ex) { - AddModuleMessage(ex.Message, MessageType.Error); + await logger.LogError(ex, "Error Saving Content {Error}", ex.Message); + AddModuleMessage("Error Saving Content", MessageType.Error); } } } diff --git a/Oqtane.Client/Modules/IModuleControl.cs b/Oqtane.Client/Modules/IModuleControl.cs index 3fd7516c..c4f2fdee 100644 --- a/Oqtane.Client/Modules/IModuleControl.cs +++ b/Oqtane.Client/Modules/IModuleControl.cs @@ -1,4 +1,6 @@ -namespace Oqtane.Modules +using Oqtane.Shared; + +namespace Oqtane.Modules { public interface IModuleControl { diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index e881a4c8..9a844e4b 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -1,16 +1,24 @@ using Microsoft.AspNetCore.Components; -using Microsoft.JSInterop; using Oqtane.Shared; using Oqtane.Models; using System.Threading.Tasks; using System.Linq; +using Oqtane.Services; +using System; namespace Oqtane.Modules { public class ModuleBase : ComponentBase, IModuleControl { + public Logger logger { get; set; } + + public ModuleBase() + { + this.logger = new Logger(this); + } + [Inject] - protected IJSRuntime JSRuntime { get; set; } + protected ILogService LoggingService { get; set; } [CascadingParameter] protected PageState PageState { get; set; } @@ -29,6 +37,7 @@ namespace Oqtane.Modules } } + // optional interface properties public virtual SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security public virtual string Title { get { return ""; } } @@ -37,11 +46,14 @@ namespace Oqtane.Modules public virtual bool UseAdminContainer { get { return true; } } + // path method + public string ModulePath() { return "Modules/" + this.GetType().Namespace + "/"; } + // url methods public string NavigateUrl() { return NavigateUrl(PageState.Page.Path); @@ -97,6 +109,7 @@ namespace Oqtane.Modules return Utilities.EditUrl(PageState.Alias.Path, path, moduleid, action, parameters); } + // user feedback methods public void AddModuleMessage(string message, MessageType type) { ModuleInstance.AddModuleMessage(message, type); @@ -111,5 +124,88 @@ namespace Oqtane.Modules { ModuleInstance.HideProgressIndicator(); } + + // logging method + public async Task Log(LogLevel level, Exception exception, string message, params object[] args) + { + int PageId = PageState.Page.PageId; + int ModuleId = ModuleState.ModuleId; + int? UserId = null; + if (PageState.User != null) + { + UserId = PageState.User.UserId; + } + await LoggingService.Log(PageId, ModuleId, UserId, this.GetType().ToString(), level, exception, message, args); + } + + public class Logger + { + private ModuleBase modulebase; + + public Logger(ModuleBase modulebase) + { + this.modulebase = modulebase; + } + + public async Task LogTrace(string message, params object[] args) + { + await modulebase.Log(LogLevel.Trace, null, message, args); + } + + public async Task LogTrace(Exception exception, string message, params object[] args) + { + await modulebase.Log(LogLevel.Trace, exception, message, args); + } + + public async Task LogDebug(string message, params object[] args) + { + await modulebase.Log(LogLevel.Debug, null, message, args); + } + + public async Task LogDebug(Exception exception, string message, params object[] args) + { + await modulebase.Log(LogLevel.Debug, exception, message, args); + } + + public async Task LogInformation(string message, params object[] args) + { + await modulebase.Log(LogLevel.Information, null, message, args); + } + + public async Task LogInformation(Exception exception, string message, params object[] args) + { + await modulebase.Log(LogLevel.Information, exception, message, args); + } + + public async Task LogWarning(string message, params object[] args) + { + await modulebase.Log(LogLevel.Warning, null, message, args); + } + + public async Task LogWarning(Exception exception, string message, params object[] args) + { + await modulebase.Log(LogLevel.Warning, exception, message, args); + } + + public async Task LogError(string message, params object[] args) + { + await modulebase.Log(LogLevel.Error, null, message, args); + } + + public async Task LogError(Exception exception, string message, params object[] args) + { + await modulebase.Log(LogLevel.Error, exception, message, args); + } + + public async Task LogCritical(string message, params object[] args) + { + await modulebase.Log(LogLevel.Critical, null, message, args); + } + + public async Task LogCritical(Exception exception, string message, params object[] args) + { + await modulebase.Log(LogLevel.Critical, exception, message, args); + } + } } } diff --git a/Oqtane.Client/Services/Interfaces/ILogService.cs b/Oqtane.Client/Services/Interfaces/ILogService.cs new file mode 100644 index 00000000..0e5361ea --- /dev/null +++ b/Oqtane.Client/Services/Interfaces/ILogService.cs @@ -0,0 +1,14 @@ +using Oqtane.Models; +using Oqtane.Shared; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Oqtane.Services +{ + public interface ILogService + { + Task> GetLogsAsync(int SiteId); + Task Log(int? PageId, int? ModuleId, int? UserId, string component, LogLevel level, Exception exception, string message, params object[] args); + } +} diff --git a/Oqtane.Client/Services/LogService.cs b/Oqtane.Client/Services/LogService.cs new file mode 100644 index 00000000..92cf9589 --- /dev/null +++ b/Oqtane.Client/Services/LogService.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Oqtane.Models; +using Oqtane.Shared; + +namespace Oqtane.Services +{ + public class LogService : ServiceBase, ILogService + { + private readonly HttpClient http; + private readonly SiteState sitestate; + private readonly NavigationManager NavigationManager; + + public LogService(HttpClient http, SiteState sitestate, NavigationManager NavigationManager) + { + this.http = http; + this.sitestate = sitestate; + this.NavigationManager = NavigationManager; + } + + private string apiurl + { + get { return CreateApiUrl(sitestate.Alias, NavigationManager.Uri, "Log"); } + } + + public async Task> GetLogsAsync(int SiteId) + { + return await http.GetJsonAsync>(apiurl + "?siteid=" + SiteId.ToString()); + } + + public async Task Log(int? PageId, int? ModuleId, int? UserId, string category, LogLevel level, Exception exception, string message, params object[] args) + { + Log log = new Log(); + log.SiteId = sitestate.Alias.SiteId; + log.PageId = PageId; + log.ModuleId = ModuleId; + log.UserId = UserId; + log.Url = NavigationManager.Uri; + log.Category = category; + log.Level = Enum.GetName(typeof(LogLevel), level); + if (exception != null) + { + log.Exception = JsonSerializer.Serialize(exception); + } + log.Message = message; + log.MessageTemplate = ""; + log.Properties = JsonSerializer.Serialize(args); + await http.PostJsonAsync(apiurl, log); + } + } +} diff --git a/Oqtane.Client/Startup.cs b/Oqtane.Client/Startup.cs index 75838511..9a114e77 100644 --- a/Oqtane.Client/Startup.cs +++ b/Oqtane.Client/Startup.cs @@ -53,6 +53,7 @@ namespace Oqtane.Client services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); // dynamically register module contexts and repository services Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); diff --git a/Oqtane.Server/Controllers/AliasController.cs b/Oqtane.Server/Controllers/AliasController.cs index cf7bbf9f..952d9de2 100644 --- a/Oqtane.Server/Controllers/AliasController.cs +++ b/Oqtane.Server/Controllers/AliasController.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Oqtane.Repository; using Oqtane.Models; using Oqtane.Shared; -using System.Linq; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -12,10 +12,12 @@ namespace Oqtane.Controllers public class AliasController : Controller { private readonly IAliasRepository Aliases; + private readonly ILogManager logger; - public AliasController(IAliasRepository Aliases) + public AliasController(IAliasRepository Aliases, ILogManager logger) { this.Aliases = Aliases; + this.logger = logger; } // GET: api/ @@ -40,6 +42,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Alias = Aliases.AddAlias(Alias); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Alias Added {Alias}", Alias); } return Alias; } @@ -52,6 +55,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Alias = Aliases.UpdateAlias(Alias); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Alias Updated {Alias}", Alias); } return Alias; } @@ -62,6 +66,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Aliases.DeleteAlias(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Alias Deleted {AliasId}", id); } } } diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 3ce2f97a..ef99bf5a 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Oqtane.Infrastructure; using Oqtane.Shared; using System; using System.Collections.Generic; @@ -15,11 +16,13 @@ namespace Oqtane.Controllers public class FileController : Controller { private readonly IWebHostEnvironment environment; + private readonly ILogManager logger; private readonly string WhiteList = "jpg,jpeg,jpe,gif,bmp,png,mov,wmv,avi,mp4,mp3,doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,nupkg"; - public FileController(IWebHostEnvironment environment) + public FileController(IWebHostEnvironment environment, ILogManager logger) { this.environment = environment; + this.logger = logger; } // GET: api/?folder=x @@ -107,6 +110,7 @@ namespace Oqtane.Controllers { // rename file now that the entire process is completed System.IO.File.Move(Path.Combine(folder, filename + ".tmp"), Path.Combine(folder, filename)); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "File Uploaded {File}", Path.Combine(folder, filename)); } } } @@ -169,6 +173,7 @@ namespace Oqtane.Controllers if (System.IO.File.Exists(file)) { System.IO.File.Delete(file); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "File Deleted {File}", file); } } diff --git a/Oqtane.Server/Controllers/LogController.cs b/Oqtane.Server/Controllers/LogController.cs new file mode 100644 index 00000000..c04dd8fc --- /dev/null +++ b/Oqtane.Server/Controllers/LogController.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Mvc; +using Oqtane.Models; +using System.Collections.Generic; +using Oqtane.Repository; +using Oqtane.Infrastructure; + +namespace Oqtane.Controllers +{ + + [Route("{site}/api/[controller]")] + public class LogController : Controller + { + private readonly ILogManager Logger; + private readonly ILogRepository Logs; + + public LogController(ILogManager Logger, ILogRepository Logs) + { + this.Logger = Logger; + this.Logs = Logs; + } + + // GET: api/?siteid=x + [HttpGet] + public IEnumerable Get(string siteid) + { + return Logs.GetLogs(int.Parse(siteid)); + } + + // POST api/ + [HttpPost] + public void Post([FromBody] Log Log) + { + if (ModelState.IsValid) + { + Logger.AddLog(Log); + } + } + } +} diff --git a/Oqtane.Server/Controllers/ModuleController.cs b/Oqtane.Server/Controllers/ModuleController.cs index e1defb0c..5b5377e5 100644 --- a/Oqtane.Server/Controllers/ModuleController.cs +++ b/Oqtane.Server/Controllers/ModuleController.cs @@ -10,6 +10,7 @@ using System; using Oqtane.Modules; using Microsoft.Extensions.DependencyInjection; using System.Text.Json; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -20,13 +21,15 @@ namespace Oqtane.Controllers private readonly IPageModuleRepository PageModules; private readonly IModuleDefinitionRepository ModuleDefinitions; private readonly IServiceProvider ServiceProvider; + private readonly ILogManager logger; - public ModuleController(IModuleRepository Modules, IPageModuleRepository PageModules, IModuleDefinitionRepository ModuleDefinitions, IServiceProvider ServiceProvider) + public ModuleController(IModuleRepository Modules, IPageModuleRepository PageModules, IModuleDefinitionRepository ModuleDefinitions, IServiceProvider ServiceProvider, ILogManager logger) { this.Modules = Modules; this.PageModules = PageModules; this.ModuleDefinitions = ModuleDefinitions; this.ServiceProvider = ServiceProvider; + this.logger = logger; } // GET: api/?siteid=x @@ -73,6 +76,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Module = Modules.AddModule(Module); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Module Added {Module}", Module); } return Module; } @@ -85,6 +89,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Module = Modules.UpdateModule(Module); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Module Updated {Module}", Module); } return Module; } @@ -95,6 +100,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Modules.DeleteModule(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Module Deleted {ModuleId}", id); } // GET api//export?moduleid=x @@ -135,6 +141,7 @@ namespace Oqtane.Controllers } } content = JsonSerializer.Serialize(modulecontent); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Module Content Exported {ModuleId}", moduleid); } } } @@ -180,6 +187,7 @@ namespace Oqtane.Controllers var moduleobject = ActivatorUtilities.CreateInstance(ServiceProvider, moduletype); ((IPortable)moduleobject).ImportModule(module, modulecontent.Content, modulecontent.Version); success = true; + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Module Content Imported {ModuleId}", moduleid); } } } diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index b418a417..8e3dd4ac 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -18,12 +18,14 @@ namespace Oqtane.Controllers private readonly IModuleDefinitionRepository ModuleDefinitions; private readonly IInstallationManager InstallationManager; private readonly IWebHostEnvironment environment; + private readonly ILogManager logger; - public ModuleDefinitionController(IModuleDefinitionRepository ModuleDefinitions, IInstallationManager InstallationManager, IWebHostEnvironment environment) + public ModuleDefinitionController(IModuleDefinitionRepository ModuleDefinitions, IInstallationManager InstallationManager, IWebHostEnvironment environment, ILogManager logger) { this.ModuleDefinitions = ModuleDefinitions; this.InstallationManager = InstallationManager; this.environment = environment; + this.logger = logger; } // GET: api/?siteid=x @@ -50,6 +52,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { ModuleDefinitions.UpdateModuleDefinition(ModuleDefinition); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Module Definition Updated {ModuleDefinition}", ModuleDefinition); } } @@ -58,6 +61,7 @@ namespace Oqtane.Controllers public void InstallModules() { InstallationManager.InstallPackages("Modules"); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Modules Installed"); } // DELETE api//5?siteid=x @@ -84,6 +88,7 @@ namespace Oqtane.Controllers } ModuleDefinitions.DeleteModuleDefinition(id, siteid); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Module Deleted {ModuleDefinitionId}", id); InstallationManager.RestartApplication(); } diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 3a08e680..58fe7ad4 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -5,6 +5,7 @@ using Oqtane.Repository; using Oqtane.Models; using Oqtane.Shared; using System.Linq; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -12,10 +13,12 @@ namespace Oqtane.Controllers public class PageController : Controller { private readonly IPageRepository Pages; + private readonly ILogManager logger; - public PageController(IPageRepository Pages) + public PageController(IPageRepository Pages, ILogManager logger) { this.Pages = Pages; + this.logger = logger; } // GET: api/?siteid=x @@ -47,6 +50,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Page = Pages.AddPage(Page); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Page Added {Page}", Page); } return Page; } @@ -59,6 +63,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Page = Pages.UpdatePage(Page); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Page Updated {Page}", Page); } return Page; } @@ -79,6 +84,7 @@ namespace Oqtane.Controllers } order += 2; } + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Page Order Updated {SiteId} {ParentId}", siteid, parentid); } // DELETE api//5 @@ -87,6 +93,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Pages.DeletePage(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Page Deleted {PageId}", id); } } } diff --git a/Oqtane.Server/Controllers/PageModuleController.cs b/Oqtane.Server/Controllers/PageModuleController.cs index 7c331e0c..d156a1d2 100644 --- a/Oqtane.Server/Controllers/PageModuleController.cs +++ b/Oqtane.Server/Controllers/PageModuleController.cs @@ -5,6 +5,7 @@ using Oqtane.Repository; using Oqtane.Models; using Oqtane.Shared; using System.Linq; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -13,11 +14,13 @@ namespace Oqtane.Controllers { private readonly IPageModuleRepository PageModules; private readonly IModuleRepository Modules; + private readonly ILogManager logger; - public PageModuleController(IPageModuleRepository PageModules, IModuleRepository Modules) + public PageModuleController(IPageModuleRepository PageModules, IModuleRepository Modules, ILogManager logger) { this.PageModules = PageModules; this.Modules = Modules; + this.logger = logger; } // GET: api/ @@ -42,6 +45,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { PageModule = PageModules.AddPageModule(PageModule); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Page Module Added {PageModule}", PageModule); } return PageModule; } @@ -54,6 +58,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { PageModule = PageModules.UpdatePageModule(PageModule); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Page Module Updated {PageModule}", PageModule); } return PageModule; } @@ -74,6 +79,7 @@ namespace Oqtane.Controllers } order += 2; } + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Page Module Order Updated {PageId} {Pane}", pageid, pane); } // DELETE api//5 @@ -82,6 +88,7 @@ namespace Oqtane.Controllers public void Delete(int id) { PageModules.DeletePageModule(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Page Module Deleted {PageModuleId}", id); } } } diff --git a/Oqtane.Server/Controllers/PermissionController.cs b/Oqtane.Server/Controllers/PermissionController.cs index dc2bc614..62d74234 100644 --- a/Oqtane.Server/Controllers/PermissionController.cs +++ b/Oqtane.Server/Controllers/PermissionController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Oqtane.Repository; using Oqtane.Models; using Oqtane.Shared; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -11,10 +12,12 @@ namespace Oqtane.Controllers public class PermissionController : Controller { private readonly IPermissionRepository Permissions; + private readonly ILogManager logger; - public PermissionController(IPermissionRepository Permissions) + public PermissionController(IPermissionRepository Permissions, ILogManager logger) { this.Permissions = Permissions; + this.logger = logger; } // GET: api/ @@ -39,6 +42,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Permission = Permissions.AddPermission(Permission); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Permission Added {Permission}", Permission); } return Permission; } @@ -51,6 +55,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Permission = Permissions.UpdatePermission(Permission); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Permission Updated {Permission}", Permission); } return Permission; } @@ -61,6 +66,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Permissions.DeletePermission(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Permission Deleted {PermissionId}", id); } } } diff --git a/Oqtane.Server/Controllers/ProfileController.cs b/Oqtane.Server/Controllers/ProfileController.cs index 7281b2a0..926a743f 100644 --- a/Oqtane.Server/Controllers/ProfileController.cs +++ b/Oqtane.Server/Controllers/ProfileController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Oqtane.Repository; using Oqtane.Models; using Oqtane.Shared; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -11,10 +12,12 @@ namespace Oqtane.Controllers public class ProfileController : Controller { private readonly IProfileRepository Profiles; + private readonly ILogManager logger; - public ProfileController(IProfileRepository Profiles) + public ProfileController(IProfileRepository Profiles, ILogManager logger) { this.Profiles = Profiles; + this.logger = logger; } // GET: api/?siteid=x @@ -46,6 +49,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Profile = Profiles.AddProfile(Profile); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Profile Added {Profile}", Profile); } return Profile; } @@ -58,6 +62,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Profile = Profiles.UpdateProfile(Profile); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Profile Updated {Profile}", Profile); } return Profile; } @@ -68,6 +73,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Profiles.DeleteProfile(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Profile Deleted {ProfileId}", id); } } } diff --git a/Oqtane.Server/Controllers/RoleController.cs b/Oqtane.Server/Controllers/RoleController.cs index 8ac711a3..a5385156 100644 --- a/Oqtane.Server/Controllers/RoleController.cs +++ b/Oqtane.Server/Controllers/RoleController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Oqtane.Repository; using Oqtane.Models; using Oqtane.Shared; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -11,10 +12,12 @@ namespace Oqtane.Controllers public class RoleController : Controller { private readonly IRoleRepository Roles; + private readonly ILogManager logger; - public RoleController(IRoleRepository Roles) + public RoleController(IRoleRepository Roles, ILogManager logger) { this.Roles = Roles; + this.logger = logger; } // GET: api/?siteid=x @@ -46,6 +49,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Role = Roles.AddRole(Role); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Role Added {Role}", Role); } return Role; } @@ -58,6 +62,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Role = Roles.UpdateRole(Role); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Role Updated {Role}", Role); } return Role; } @@ -68,6 +73,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Roles.DeleteRole(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Role Deleted {RoleId}", id); } } } diff --git a/Oqtane.Server/Controllers/SettingController.cs b/Oqtane.Server/Controllers/SettingController.cs index 2d400cca..26a24901 100644 --- a/Oqtane.Server/Controllers/SettingController.cs +++ b/Oqtane.Server/Controllers/SettingController.cs @@ -5,6 +5,7 @@ using Oqtane.Repository; using Oqtane.Models; using Oqtane.Shared; using Oqtane.Security; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -13,11 +14,13 @@ namespace Oqtane.Controllers { private readonly ISettingRepository Settings; private readonly IUserPermissions UserPermissions; + private readonly ILogManager logger; - public SettingController(ISettingRepository Settings, IUserPermissions UserPermissions) + public SettingController(ISettingRepository Settings, IUserPermissions UserPermissions, ILogManager logger) { this.Settings = Settings; this.UserPermissions = UserPermissions; + this.logger = logger; } // GET: api/ @@ -42,6 +45,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && IsAuthorized(Setting.EntityName, Setting.EntityId)) { Setting = Settings.AddSetting(Setting); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Setting Added {Setting}", Setting); } return Setting; } @@ -54,6 +58,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && IsAuthorized(Setting.EntityName, Setting.EntityId)) { Setting = Settings.UpdateSetting(Setting); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Setting Updated {Setting}", Setting); } return Setting; } @@ -64,6 +69,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Settings.DeleteSetting(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Setting Deleted {SettingId}", id); } private bool IsAuthorized(string EntityName, int EntityId) diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index 03e28e8b..74e668a0 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -7,6 +7,7 @@ using Oqtane.Shared; using System.Linq; using System.IO; using Microsoft.AspNetCore.Hosting; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -16,12 +17,14 @@ namespace Oqtane.Controllers private readonly ISiteRepository Sites; private readonly ITenantResolver Tenants; private readonly IWebHostEnvironment environment; + private readonly ILogManager logger; - public SiteController(ISiteRepository Sites, ITenantResolver Tenants, IWebHostEnvironment environment) + public SiteController(ISiteRepository Sites, ITenantResolver Tenants, IWebHostEnvironment environment, ILogManager logger) { this.Sites = Sites; this.Tenants = Tenants; this.environment = environment; + this.logger = logger; } // GET: api/ @@ -61,6 +64,7 @@ namespace Oqtane.Controllers { Directory.CreateDirectory(folder); } + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Site Added {Site}", Site); } } return Site; @@ -74,6 +78,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Site = Sites.UpdateSite(Site); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Site Updated {Site}", Site); } return Site; } @@ -84,6 +89,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Sites.DeleteSite(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Site Deleted {SiteId}", id); } } } diff --git a/Oqtane.Server/Controllers/TenantController.cs b/Oqtane.Server/Controllers/TenantController.cs index 1711aae1..22400722 100644 --- a/Oqtane.Server/Controllers/TenantController.cs +++ b/Oqtane.Server/Controllers/TenantController.cs @@ -4,6 +4,7 @@ using Oqtane.Repository; using Oqtane.Models; using System.Collections.Generic; using Oqtane.Shared; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -11,10 +12,12 @@ namespace Oqtane.Controllers public class TenantController : Controller { private readonly ITenantRepository Tenants; + private readonly ILogManager logger; - public TenantController(ITenantRepository Tenants) + public TenantController(ITenantRepository Tenants, ILogManager logger) { this.Tenants = Tenants; + this.logger = logger; } // GET: api/ @@ -39,6 +42,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Tenant = Tenants.AddTenant(Tenant); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Tenant Added {TenantId}", Tenant.TenantId); } return Tenant; } @@ -51,6 +55,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { Tenant = Tenants.UpdateTenant(Tenant); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Tenant Updated {TenantId}", Tenant.TenantId); } return Tenant; } @@ -61,6 +66,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Tenants.DeleteTenant(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Tenant Deleted {TenantId}", id); } } } diff --git a/Oqtane.Server/Controllers/ThemeController.cs b/Oqtane.Server/Controllers/ThemeController.cs index 076a57b2..64834b15 100644 --- a/Oqtane.Server/Controllers/ThemeController.cs +++ b/Oqtane.Server/Controllers/ThemeController.cs @@ -18,12 +18,14 @@ namespace Oqtane.Controllers private readonly IThemeRepository Themes; private readonly IInstallationManager InstallationManager; private readonly IWebHostEnvironment environment; + private readonly ILogManager logger; - public ThemeController(IThemeRepository Themes, IInstallationManager InstallationManager, IWebHostEnvironment environment) + public ThemeController(IThemeRepository Themes, IInstallationManager InstallationManager, IWebHostEnvironment environment, ILogManager logger) { this.Themes = Themes; this.InstallationManager = InstallationManager; this.environment = environment; + this.logger = logger; } // GET: api/ @@ -47,6 +49,7 @@ namespace Oqtane.Controllers public void InstallThemes() { InstallationManager.InstallPackages("Themes"); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Themes Installed"); } // DELETE api//xxx @@ -71,6 +74,7 @@ namespace Oqtane.Controllers { System.IO.File.Delete(file); } + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Theme Deleted {ThemeName}", themename); InstallationManager.RestartApplication(); } diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index a2bbd4bd..e96f4e89 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using System.Linq; using System.Security.Claims; using Oqtane.Shared; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -20,14 +21,16 @@ namespace Oqtane.Controllers private readonly IUserRoleRepository UserRoles; private readonly UserManager IdentityUserManager; private readonly SignInManager IdentitySignInManager; + private readonly ILogManager logger; - public UserController(IUserRepository Users, IRoleRepository Roles, IUserRoleRepository UserRoles, UserManager IdentityUserManager, SignInManager IdentitySignInManager) + public UserController(IUserRepository Users, IRoleRepository Roles, IUserRoleRepository UserRoles, UserManager IdentityUserManager, SignInManager IdentitySignInManager, ILogManager logger) { this.Users = Users; this.Roles = Roles; this.UserRoles = UserRoles; this.IdentityUserManager = IdentityUserManager; this.IdentitySignInManager = IdentitySignInManager; + this.logger = logger; } // GET: api/?siteid=x @@ -123,6 +126,8 @@ namespace Oqtane.Controllers UserRoles.AddUserRole(userrole); } } + user.Password = ""; // remove sensitive information + logger.AddLog(this.GetType().FullName, LogLevel.Information, "User Added {User}", user); } return user; @@ -145,6 +150,8 @@ namespace Oqtane.Controllers } } User = Users.UpdateUser(User); + User.Password = ""; // remove sensitive information + logger.AddLog(this.GetType().FullName, LogLevel.Information, "User Updated {User}", User); } return User; } @@ -163,6 +170,7 @@ namespace Oqtane.Controllers if (result != null) { Users.DeleteUser(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "User Deleted {UserId}", id); } } } @@ -185,12 +193,17 @@ namespace Oqtane.Controllers if (user != null) { user.IsAuthenticated = true; + logger.AddLog(this.GetType().FullName, LogLevel.Information, "User Login Successful {Username}", User.Username); if (SetCookie) { await IdentitySignInManager.SignInAsync(identityuser, IsPersistent); } } } + else + { + logger.AddLog(this.GetType().FullName, LogLevel.Error, "User Login Failed {Username}", User.Username); + } } } @@ -203,6 +216,7 @@ namespace Oqtane.Controllers public async Task Logout([FromBody] User User) { await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "User Logout {Username}", User.Username); } // GET api//current diff --git a/Oqtane.Server/Controllers/UserRoleController.cs b/Oqtane.Server/Controllers/UserRoleController.cs index 07daee27..4dd603dd 100644 --- a/Oqtane.Server/Controllers/UserRoleController.cs +++ b/Oqtane.Server/Controllers/UserRoleController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Oqtane.Repository; using Oqtane.Models; using Oqtane.Shared; +using Oqtane.Infrastructure; namespace Oqtane.Controllers { @@ -11,10 +12,12 @@ namespace Oqtane.Controllers public class UserRoleController : Controller { private readonly IUserRoleRepository UserRoles; + private readonly ILogManager logger; - public UserRoleController(IUserRoleRepository UserRoles) + public UserRoleController(IUserRoleRepository UserRoles, ILogManager logger) { this.UserRoles = UserRoles; + this.logger = logger; } // GET: api/?userid=x @@ -46,6 +49,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { UserRole = UserRoles.AddUserRole(UserRole); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "User Role Added {UserRole}", UserRole); } return UserRole; } @@ -58,6 +62,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { UserRole = UserRoles.UpdateUserRole(UserRole); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "User Role Updated {UserRole}", UserRole); } return UserRole; } @@ -68,6 +73,7 @@ namespace Oqtane.Controllers public void Delete(int id) { UserRoles.DeleteUserRole(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "User Role Deleted {UserRoleId}", id); } } } diff --git a/Oqtane.Server/Infrastructure/ILogManager.cs b/Oqtane.Server/Infrastructure/ILogManager.cs new file mode 100644 index 00000000..e49efe66 --- /dev/null +++ b/Oqtane.Server/Infrastructure/ILogManager.cs @@ -0,0 +1,13 @@ +using Oqtane.Models; +using Oqtane.Shared; +using System; + +namespace Oqtane.Infrastructure +{ + public interface ILogManager + { + void AddLog(string Category, LogLevel Level, string Message, params object[] Args); + void AddLog(string Category, LogLevel Level, Exception Exception, string Message, params object[] Args); + void AddLog(Log Log); + } +} diff --git a/Oqtane.Server/Infrastructure/LogManager.cs b/Oqtane.Server/Infrastructure/LogManager.cs new file mode 100644 index 00000000..319cf3aa --- /dev/null +++ b/Oqtane.Server/Infrastructure/LogManager.cs @@ -0,0 +1,128 @@ +using Oqtane.Shared; +using System; +using Oqtane.Models; +using System.Text.Json; +using Oqtane.Repository; +using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Http; +using System.Security.Claims; +using System.Collections.Generic; + +namespace Oqtane.Infrastructure +{ + public class LogManager : ILogManager + { + private readonly ILogRepository Logs; + private readonly ITenantResolver TenantResolver; + private readonly IConfigurationRoot Config; + private readonly IHttpContextAccessor Accessor; + + public LogManager(ILogRepository Logs, ITenantResolver TenantResolver, IConfigurationRoot Config, IHttpContextAccessor Accessor) + { + this.Logs = Logs; + this.TenantResolver = TenantResolver; + this.Config = Config; + this.Accessor = Accessor; + } + + public void AddLog(string Category, LogLevel Level, string Message, params object[] Args) + { + AddLog(Category, Level, null, Message, Args); + } + + public void AddLog(string Category, LogLevel Level, Exception Exception, string Message, params object[] Args) + { + Alias alias = TenantResolver.GetAlias(); + Log log = new Log(); + log.SiteId = alias.SiteId; + log.PageId = null; + log.ModuleId = null; + if (Accessor.HttpContext.User.FindFirst(ClaimTypes.PrimarySid) != null) + { + log.UserId = int.Parse(Accessor.HttpContext.User.FindFirst(ClaimTypes.PrimarySid).Value); + } + HttpRequest request = Accessor.HttpContext.Request; + if (request != null) + { + log.Url = request.Scheme.ToString() + "://" + request.Host.ToString() + request.Path.ToString() + request.QueryString.ToString(); + } + + log.Category = Category; + log.Level = Enum.GetName(typeof(LogLevel), Level); + if (Exception != null) + { + log.Exception = JsonSerializer.Serialize(Exception); + } + log.Message = Message; + log.MessageTemplate = ""; + log.Properties = JsonSerializer.Serialize(Args); + AddLog(log); + } + + public void AddLog(Log Log) + { + LogLevel minlevel = LogLevel.Information; + var section = Config.GetSection("Logging:LogLevel:Default"); + if (section.Exists()) + { + minlevel = Enum.Parse(Config.GetSection("Logging:LogLevel:Default").ToString()); + } + + if (Enum.Parse(Log.Level) >= minlevel) + { + Log.LogDate = DateTime.UtcNow; + Log.Server = Environment.MachineName; + Log.MessageTemplate = Log.Message; + Log = ProcessStructuredLog(Log); + Logs.AddLog(Log); + } + } + + private Log ProcessStructuredLog(Log Log) + { + string message = Log.Message; + string properties = ""; + if (!string.IsNullOrEmpty(message) && message.Contains("{") && message.Contains("}") && !string.IsNullOrEmpty(Log.Properties)) + { + // get the named holes in the message and replace values + object[] values = JsonSerializer.Deserialize(Log.Properties); + List names = new List(); + int index = message.IndexOf("{"); + while (index != -1) + { + if (message.IndexOf("}", index) != -1) + { + names.Add(message.Substring(index + 1, message.IndexOf("}", index) - index - 1)); + if (values.Length > (names.Count - 1)) + { + message = message.Replace("{" + names[names.Count - 1] + "}", values[names.Count - 1].ToString()); + } + } + index = message.IndexOf("{", index + 1); + } + // rebuild properties into dictionary + Dictionary propertydictionary = new Dictionary(); + for (int i = 0; i < values.Length; i++) + { + string value = ""; + if (values[i] != null) + { + value = values[i].ToString(); + } + if (i < names.Count) + { + propertydictionary.Add(names[i], value); + } + else + { + propertydictionary.Add("Property" + i.ToString(), value); + } + } + properties = JsonSerializer.Serialize(propertydictionary); + } + Log.Message = message; + Log.Properties = properties; + return Log; + } + } +} \ No newline at end of file diff --git a/Oqtane.Server/Logging/DBLoggerExtensions.cs b/Oqtane.Server/Logging/DBLoggerExtensions.cs deleted file mode 100644 index 16623d85..00000000 --- a/Oqtane.Server/Logging/DBLoggerExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; - -namespace Oqtane.Logging -{ - static public class DBLoggerExtensions - { - static public ILoggingBuilder AddDBLogger(this ILoggingBuilder builder) - { - builder.AddConfiguration(); - - builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); - builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, DBLoggerOptionsSetup>()); - builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton, LoggerProviderOptionsChangeTokenSource>()); - return builder; - } - - static public ILoggingBuilder AddDBLogger(this ILoggingBuilder builder, Action configure) - { - if (configure == null) - { - throw new ArgumentNullException(nameof(configure)); - } - - builder.AddDBLogger(); - builder.Services.Configure(configure); - - return builder; - } - } -} diff --git a/Oqtane.Server/Logging/DBLoggerOptions.cs b/Oqtane.Server/Logging/DBLoggerOptions.cs deleted file mode 100644 index 9c9edba0..00000000 --- a/Oqtane.Server/Logging/DBLoggerOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.Extensions.Logging; - -namespace Oqtane.Logging -{ - public class DBLoggerOptions - { - public DBLoggerOptions() - { - } - - public LogLevel LogLevel { get; set; } = LogLevel.Information; - } -} diff --git a/Oqtane.Server/Logging/DBLoggerOptionsSetup.cs b/Oqtane.Server/Logging/DBLoggerOptionsSetup.cs deleted file mode 100644 index fece7ba3..00000000 --- a/Oqtane.Server/Logging/DBLoggerOptionsSetup.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging.Configuration; - -namespace Oqtane.Logging -{ - internal class DBLoggerOptionsSetup : ConfigureFromConfigurationOptions - { - public DBLoggerOptionsSetup(ILoggerProviderConfiguration providerConfiguration) - : base(providerConfiguration.Configuration) {} - } -} diff --git a/Oqtane.Server/Logging/DBLoggerProvider.cs b/Oqtane.Server/Logging/DBLoggerProvider.cs deleted file mode 100644 index b9feefc7..00000000 --- a/Oqtane.Server/Logging/DBLoggerProvider.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Collections.Concurrent; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging; -using Oqtane.Models; -using Oqtane.Repository; - -namespace Oqtane.Logging -{ - [Microsoft.Extensions.Logging.ProviderAlias("DB")] - public class DBLoggerProvider : LoggerProvider - { - bool Terminated; - ConcurrentQueue LogQueue = new ConcurrentQueue(); - private Tenant tenant; - internal DBLoggerOptions Settings { get; private set; } - - public DBLoggerProvider(ITenantResolver TenantResolver) - { - tenant = TenantResolver.GetTenant(); - } - - public override void WriteLog(LogEntry LogEntry) - { - // enrich with tenant information - LogQueue.Enqueue(LogEntry); - } - - void ThreadProc() - { - Task.Run(() => { - - while (!Terminated) - { - try - { - AddLogEntry(); - System.Threading.Thread.Sleep(100); - } - catch - { - } - } - - }); - } - - void AddLogEntry() - { - // check the LogQueue.Count to determine if a threshold has been reached - // then dequeue the items into temp storage based on TenantId and bulk insert them into the database - LogEntry logentry = null; - if (LogQueue.TryDequeue(out logentry)) - { - // convert logentry object to object which can be stored in database - } - - } - - protected override void Dispose(bool Disposing) - { - Terminated = true; - base.Dispose(Disposing); - } - - public DBLoggerProvider(IOptionsMonitor Settings) - : this(Settings.CurrentValue) - { - SettingsChangeToken = Settings.OnChange(settings => { - this.Settings = settings; - }); - } - - public DBLoggerProvider(DBLoggerOptions Settings) - { - this.Settings = Settings; - ThreadProc(); - } - - public override bool IsEnabled(LogLevel LogLevel) - { - bool Result = LogLevel != LogLevel.None - && this.Settings.LogLevel != LogLevel.None - && Convert.ToInt32(LogLevel) >= Convert.ToInt32(this.Settings.LogLevel); - - return Result; - } - - - - - } -} diff --git a/Oqtane.Server/Logging/LogEntry.cs b/Oqtane.Server/Logging/LogEntry.cs deleted file mode 100644 index 2e9ae122..00000000 --- a/Oqtane.Server/Logging/LogEntry.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.Extensions.Logging; -using Oqtane.Models; -using Oqtane.Repository; -using System; -using System.Collections.Generic; - -namespace Oqtane.Logging -{ - public class LogEntry - { - public LogEntry() - { - TimeStampUtc = DateTime.UtcNow; - UserName = Environment.UserName; - } - - static public readonly string StaticHostName = System.Net.Dns.GetHostName(); - - public string UserName { get; private set; } - public string HostName { get { return StaticHostName; } } - public DateTime TimeStampUtc { get; private set; } - public string Category { get; set; } - public LogLevel Level { get; set; } - public string Text { get; set; } - public Exception Exception { get; set; } - public EventId EventId { get; set; } - public object State { get; set; } - public string StateText { get; set; } - public Dictionary StateProperties { get; set; } - public List Scopes { get; set; } - } -} diff --git a/Oqtane.Server/Logging/LogScope.cs b/Oqtane.Server/Logging/LogScope.cs deleted file mode 100644 index 8c3de6ce..00000000 --- a/Oqtane.Server/Logging/LogScope.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace Oqtane.Logging -{ - public class LogScope - { - public string Text { get; set; } - public Dictionary Properties { get; set; } - } -} diff --git a/Oqtane.Server/Logging/Logger.cs b/Oqtane.Server/Logging/Logger.cs deleted file mode 100644 index 648cb885..00000000 --- a/Oqtane.Server/Logging/Logger.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Logging; - -namespace Oqtane.Logging -{ - internal class Logger : ILogger - { - public LoggerProvider Provider { get; private set; } - public string Category { get; private set; } - - public Logger(LoggerProvider Provider, string Category) - { - this.Provider = Provider; - this.Category = Category; - } - - IDisposable ILogger.BeginScope(TState State) - { - return Provider.ScopeProvider.Push(State); - } - - bool ILogger.IsEnabled(LogLevel LogLevel) - { - return Provider.IsEnabled(LogLevel); - } - - void ILogger.Log(LogLevel LogLevel, EventId EventId, TState State, Exception Exception, Func Formatter) - { - if ((this as ILogger).IsEnabled(LogLevel)) - { - - LogEntry logentry = new LogEntry(); - // we need the TenantId and SiteId - logentry.Category = this.Category; - logentry.Level = LogLevel; - logentry.Text = Exception?.Message ?? State.ToString(); - logentry.Exception = Exception; - logentry.EventId = EventId; - logentry.State = State; - - if (State is string) - { - logentry.StateText = State.ToString(); - } - else if (State is IEnumerable> Properties) - { - logentry.StateProperties = new Dictionary(); - - foreach (KeyValuePair item in Properties) - { - logentry.StateProperties[item.Key] = item.Value; - } - } - - if (Provider.ScopeProvider != null) - { - Provider.ScopeProvider.ForEachScope((value, loggingProps) => - { - if (logentry.Scopes == null) - { - logentry.Scopes = new List(); - } - - LogScope Scope = new LogScope(); - logentry.Scopes.Add(Scope); - - if (value is string) - { - Scope.Text = value.ToString(); - } - else if (value is IEnumerable> props) - { - if (Scope.Properties == null) - Scope.Properties = new Dictionary(); - - foreach (var pair in props) - { - Scope.Properties[pair.Key] = pair.Value; - } - } - }, State); - - } - - Provider.WriteLog(logentry); - } - } - - } -} \ No newline at end of file diff --git a/Oqtane.Server/Logging/LoggerProvider.cs b/Oqtane.Server/Logging/LoggerProvider.cs deleted file mode 100644 index 10385aac..00000000 --- a/Oqtane.Server/Logging/LoggerProvider.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Concurrent; -using Microsoft.Extensions.Logging; - -namespace Oqtane.Logging -{ - public abstract class LoggerProvider : IDisposable, ILoggerProvider, ISupportExternalScope - { - ConcurrentDictionary loggers = new ConcurrentDictionary(); - IExternalScopeProvider fScopeProvider; - protected IDisposable SettingsChangeToken; - - void ISupportExternalScope.SetScopeProvider(IExternalScopeProvider ScopeProvider) - { - fScopeProvider = ScopeProvider; - } - - ILogger ILoggerProvider.CreateLogger(string Category) - { - return loggers.GetOrAdd(Category, - (category) => { - return new Logger(this, category); - }); - } - - void IDisposable.Dispose() - { - if (!this.IsDisposed) - { - try - { - Dispose(true); - } - catch - { - } - - this.IsDisposed = true; - GC.SuppressFinalize(this); - } - } - - protected virtual void Dispose(bool Disposing) - { - if (SettingsChangeToken != null) - { - SettingsChangeToken.Dispose(); - SettingsChangeToken = null; - } - } - - public LoggerProvider() - { - } - - ~LoggerProvider() - { - if (!this.IsDisposed) - { - Dispose(false); - } - } - - public abstract bool IsEnabled(LogLevel LogLevel); - - public abstract void WriteLog(LogEntry LogEntry); - - internal IExternalScopeProvider ScopeProvider - { - get - { - if (fScopeProvider == null) - fScopeProvider = new LoggerExternalScopeProvider(); - return fScopeProvider; - } - } - - public bool IsDisposed { get; protected set; } - } -} \ No newline at end of file diff --git a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs index 761b4f37..1f78f57d 100644 --- a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs +++ b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs @@ -3,18 +3,22 @@ using Microsoft.AspNetCore.Authorization; using Oqtane.Modules.HtmlText.Models; using Oqtane.Modules.HtmlText.Repository; using Microsoft.AspNetCore.Http; +using Oqtane.Infrastructure; +using Oqtane.Shared; namespace Oqtane.Modules.HtmlText.Controllers { [Route("{site}/api/[controller]")] public class HtmlTextController : Controller { - private IHtmlTextRepository htmltext; + private readonly IHtmlTextRepository htmltext; + private readonly ILogManager logger; private int EntityId = -1; // passed as a querystring parameter for authorization and used for validation - public HtmlTextController(IHtmlTextRepository HtmlText, IHttpContextAccessor HttpContextAccessor) + public HtmlTextController(IHtmlTextRepository HtmlText, ILogManager logger, IHttpContextAccessor HttpContextAccessor) { htmltext = HtmlText; + this.logger = logger; if (HttpContextAccessor.HttpContext.Request.Query.ContainsKey("entityid")) { EntityId = int.Parse(HttpContextAccessor.HttpContext.Request.Query["entityid"]); @@ -42,6 +46,7 @@ namespace Oqtane.Modules.HtmlText.Controllers if (ModelState.IsValid && HtmlText.ModuleId == EntityId) { HtmlText = htmltext.AddHtmlText(HtmlText); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Html/Text Added {HtmlText}", HtmlText); } return HtmlText; } @@ -54,6 +59,7 @@ namespace Oqtane.Modules.HtmlText.Controllers if (ModelState.IsValid && HtmlText.ModuleId == EntityId) { HtmlText = htmltext.UpdateHtmlText(HtmlText); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Html/Text Updated {HtmlText}", HtmlText); } return HtmlText; } @@ -66,6 +72,7 @@ namespace Oqtane.Modules.HtmlText.Controllers if (id == EntityId) { htmltext.DeleteHtmlText(id); + logger.AddLog(this.GetType().FullName, LogLevel.Information, "Html/Text Deleted {HtmlTextId}", id); } } } diff --git a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs index 2aa3b5b4..2ff3e6d2 100644 --- a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs +++ b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextContext.cs @@ -1,7 +1,6 @@ using Microsoft.EntityFrameworkCore; using Oqtane.Modules.HtmlText.Models; using Oqtane.Repository; -using Oqtane.Modules; using Microsoft.AspNetCore.Http; namespace Oqtane.Modules.HtmlText.Repository diff --git a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs index 9cda535b..79befc7b 100644 --- a/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs +++ b/Oqtane.Server/Modules/HtmlText/Repository/HtmlTextRepository.cs @@ -1,8 +1,6 @@ using Microsoft.EntityFrameworkCore; -using System.Collections.Generic; using System.Linq; using Oqtane.Modules.HtmlText.Models; -using Oqtane.Modules; namespace Oqtane.Modules.HtmlText.Repository { diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 400acb30..fca66b6f 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -43,7 +43,6 @@ - diff --git a/Oqtane.Server/Program.cs b/Oqtane.Server/Program.cs index 180d79f3..ca26b836 100644 --- a/Oqtane.Server/Program.cs +++ b/Oqtane.Server/Program.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.Blazor.Hosting; +// used by client-side Blazor using Microsoft.Extensions.Configuration; using Microsoft.AspNetCore; diff --git a/Oqtane.Server/Repository/Context/TenantDBContext.cs b/Oqtane.Server/Repository/Context/TenantDBContext.cs index 1465de45..490c5eff 100644 --- a/Oqtane.Server/Repository/Context/TenantDBContext.cs +++ b/Oqtane.Server/Repository/Context/TenantDBContext.cs @@ -16,6 +16,7 @@ namespace Oqtane.Repository public virtual DbSet UserRole { get; set; } public virtual DbSet Permission { get; set; } public virtual DbSet Setting { get; set; } + public virtual DbSet Log { get; set; } public TenantDBContext(ITenantResolver TenantResolver, IHttpContextAccessor accessor) : base(TenantResolver, accessor) { diff --git a/Oqtane.Server/Repository/Interfaces/ILogRepository.cs b/Oqtane.Server/Repository/Interfaces/ILogRepository.cs new file mode 100644 index 00000000..159fe2b6 --- /dev/null +++ b/Oqtane.Server/Repository/Interfaces/ILogRepository.cs @@ -0,0 +1,11 @@ +using Oqtane.Models; +using System.Collections.Generic; + +namespace Oqtane.Repository +{ + public interface ILogRepository + { + void AddLog(Log Log); + IEnumerable GetLogs(int SiteId); + } +} diff --git a/Oqtane.Server/Repository/LogRepository.cs b/Oqtane.Server/Repository/LogRepository.cs new file mode 100644 index 00000000..295d7049 --- /dev/null +++ b/Oqtane.Server/Repository/LogRepository.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using Oqtane.Models; + +namespace Oqtane.Repository +{ + public class LogRepository : ILogRepository + { + private TenantDBContext db; + + public LogRepository(TenantDBContext context) + { + db = context; + } + + public void AddLog(Log Log) + { + db.Log.Add(Log); + db.SaveChanges(); + } + + public IEnumerable GetLogs(int SiteId) + { + return db.Log.Where(item => item.SiteId == SiteId).OrderByDescending(item=> item.LogDate).Take(50); + } + } +} diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 6d9a43b5..555e8d2f 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -68,6 +68,9 @@ namespace Oqtane.Repository SiteTemplate.Add(new PageTemplate { Name = "Role Management", Parent = "Admin", Path = "admin/roles", Icon = "lock-locked", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Roles, Oqtane.Client", Title = "Role Management", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" } }}); + SiteTemplate.Add(new PageTemplate { Name = "Event Log", Parent = "Admin", Path = "admin/log", Icon = "magnifying-glass", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Logs, Oqtane.Client", Title = "Event Log", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" } + }}); SiteTemplate.Add(new PageTemplate { Name = "Tenant Management", Parent = "Admin", Path = "admin/tenants", Icon = "list", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Tenants, Oqtane.Client", Title = "Tenant Management", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" } }}); @@ -80,8 +83,8 @@ namespace Oqtane.Repository SiteTemplate.Add(new PageTemplate { Name = "Upgrade Service", Parent = "Admin", Path = "admin/upgrade", Icon = "aperture", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Upgrade, Oqtane.Client", Title = "Upgrade Service", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" } }}); - SiteTemplate.Add(new PageTemplate { Name = "RecycleBin", Parent = "Admin", Path = "admin/recyclebin", Icon = "trash", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.RecycleBin, Oqtane.Client", Title = "RecycleBin", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" } + SiteTemplate.Add(new PageTemplate { Name = "Recycle Bin", Parent = "Admin", Path = "admin/recyclebin", Icon = "trash", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.RecycleBin, Oqtane.Client", Title = "Recycle Bin", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Login", Parent = "", Path = "login", Icon = "lock-locked", IsNavigation = false, EditMode = false, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Login, Oqtane.Client", Title = "User Login", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" } diff --git a/Oqtane.Server/Scripts/00.00.00.sql b/Oqtane.Server/Scripts/00.00.00.sql index 34013954..d78e545d 100644 --- a/Oqtane.Server/Scripts/00.00.00.sql +++ b/Oqtane.Server/Scripts/00.00.00.sql @@ -204,6 +204,30 @@ CREATE TABLE [dbo].[Profile]( GO +CREATE TABLE [dbo].[Log] ( + + [LogId] [int] IDENTITY(1,1) NOT NULL, + [SiteId] [int] NOT NULL, + [LogDate] [datetime] NOT NULL, + [PageId] [int] NULL, + [ModuleId] [int] NULL, + [UserId] [int] NULL, + [Url] [nvarchar](200) NOT NULL, + [Server] [nvarchar](200) NOT NULL, + [Category] [nvarchar](200) NOT NULL, + [Level] [nvarchar](20) NOT NULL, + [Message] [nvarchar](max) NOT NULL, + [MessageTemplate] [nvarchar](max) NOT NULL, + [Exception] [nvarchar](max) NULL, + [Properties] [nvarchar](max) NULL + + CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED + ( + [LogId] ASC + ) +) +GO + CREATE TABLE [dbo].[HtmlText]( [HtmlTextId] [int] IDENTITY(1,1) NOT NULL, [ModuleId] [int] NOT NULL, @@ -275,6 +299,11 @@ REFERENCES [dbo].[Site] ([SiteId]) ON DELETE CASCADE GO +ALTER TABLE [dbo].[Log] WITH CHECK ADD CONSTRAINT [FK_Log_Site] FOREIGN KEY([SiteId]) +REFERENCES [dbo].[Site] ([SiteId]) +ON DELETE CASCADE +GO + ALTER TABLE [dbo].[HtmlText] WITH CHECK ADD CONSTRAINT [FK_HtmlText_Module] FOREIGN KEY([ModuleId]) REFERENCES [dbo].[Module] ([ModuleId]) ON DELETE CASCADE diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index b68430e1..4e6b8806 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -99,6 +99,7 @@ namespace Oqtane.Server services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddSingleton(); @@ -173,6 +174,8 @@ namespace Oqtane.Server services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); // get list of loaded assemblies Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); @@ -360,6 +363,8 @@ namespace Oqtane.Server services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); // get list of loaded assemblies Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); diff --git a/Oqtane.Server/wwwroot/Tenants/1/Sites/1/Softvision Pen.jpg b/Oqtane.Server/wwwroot/Tenants/1/Sites/1/Softvision Pen.jpg new file mode 100644 index 00000000..f184f2ad Binary files /dev/null and b/Oqtane.Server/wwwroot/Tenants/1/Sites/1/Softvision Pen.jpg differ diff --git a/Oqtane.Shared/Enums/LogLevel.cs b/Oqtane.Shared/Enums/LogLevel.cs new file mode 100644 index 00000000..f772157e --- /dev/null +++ b/Oqtane.Shared/Enums/LogLevel.cs @@ -0,0 +1,12 @@ +namespace Oqtane.Shared +{ + public enum LogLevel + { + Trace, + Debug, + Information, + Warning, + Error, + Critical + } +} diff --git a/Oqtane.Shared/Modules/SecurityAccessLevel.cs b/Oqtane.Shared/Enums/SecurityAccessLevel.cs similarity index 81% rename from Oqtane.Shared/Modules/SecurityAccessLevel.cs rename to Oqtane.Shared/Enums/SecurityAccessLevel.cs index abaf4f6e..7b993b60 100644 --- a/Oqtane.Shared/Modules/SecurityAccessLevel.cs +++ b/Oqtane.Shared/Enums/SecurityAccessLevel.cs @@ -1,4 +1,4 @@ -namespace Oqtane.Modules +namespace Oqtane.Shared { public enum SecurityAccessLevel { diff --git a/Oqtane.Shared/Models/IAuditable.cs b/Oqtane.Shared/Interfaces/IAuditable.cs similarity index 100% rename from Oqtane.Shared/Models/IAuditable.cs rename to Oqtane.Shared/Interfaces/IAuditable.cs diff --git a/Oqtane.Shared/Models/IDeletable.cs b/Oqtane.Shared/Interfaces/IDeletable.cs similarity index 100% rename from Oqtane.Shared/Models/IDeletable.cs rename to Oqtane.Shared/Interfaces/IDeletable.cs diff --git a/Oqtane.Shared/Modules/IService.cs b/Oqtane.Shared/Interfaces/IService.cs similarity index 100% rename from Oqtane.Shared/Modules/IService.cs rename to Oqtane.Shared/Interfaces/IService.cs diff --git a/Oqtane.Shared/Models/Log.cs b/Oqtane.Shared/Models/Log.cs new file mode 100644 index 00000000..b25d8845 --- /dev/null +++ b/Oqtane.Shared/Models/Log.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Oqtane.Models +{ + public class Log + { + public int LogId { get; set; } + public int SiteId { get; set; } + public DateTime LogDate { get; set; } + public int? PageId { get; set; } + public int? ModuleId { get; set; } + public int? UserId { get; set; } + public string Url { get; set; } + public string Server { get; set; } + public string Category { get; set; } + public string Level { get; set; } + public string Message { get; set; } + public string MessageTemplate { get; set; } + public string Exception { get; set; } + public string Properties { get; set; } + } +} diff --git a/Oqtane.Shared/Models/Module.cs b/Oqtane.Shared/Models/Module.cs index 09393b0a..4bd28269 100644 --- a/Oqtane.Shared/Models/Module.cs +++ b/Oqtane.Shared/Models/Module.cs @@ -1,4 +1,5 @@ using Oqtane.Modules; +using Oqtane.Shared; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema;