diff --git a/ProjectLighthouse/Controllers/Website/ExternalAuth/AuthenticationController.cs b/ProjectLighthouse/Controllers/Website/ExternalAuth/AuthenticationController.cs index 323ea19f..045d4cd4 100644 --- a/ProjectLighthouse/Controllers/Website/ExternalAuth/AuthenticationController.cs +++ b/ProjectLighthouse/Controllers/Website/ExternalAuth/AuthenticationController.cs @@ -7,7 +7,7 @@ using LBPUnion.ProjectLighthouse.Types; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -namespace LBPUnion.ProjectLighthouse.Controllers.ExternalAuth +namespace LBPUnion.ProjectLighthouse.Controllers.Website.ExternalAuth { [ApiController] [Route("/authentication")] diff --git a/ProjectLighthouse/Helpers/CommandHelper.cs b/ProjectLighthouse/Helpers/MaintenanceHelper.cs similarity index 53% rename from ProjectLighthouse/Helpers/CommandHelper.cs rename to ProjectLighthouse/Helpers/MaintenanceHelper.cs index cf824029..90d9c5b3 100644 --- a/ProjectLighthouse/Helpers/CommandHelper.cs +++ b/ProjectLighthouse/Helpers/MaintenanceHelper.cs @@ -1,23 +1,32 @@ +#nullable enable using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; -using LBPUnion.ProjectLighthouse.CommandLine; +using LBPUnion.ProjectLighthouse.Maintenance; namespace LBPUnion.ProjectLighthouse.Helpers { - public static class CommandHelper + public static class MaintenanceHelper { public static List Commands { get; } - static CommandHelper() + public static List MaintenanceJobs { get; } + + private static List getListOfInterfaceObjects() where T : class { - Commands = Assembly.GetExecutingAssembly() + return Assembly.GetExecutingAssembly() .GetTypes() - .Where(t => t.GetInterfaces().Contains(typeof(ICommand)) && t.GetConstructor(Type.EmptyTypes) != null) - .Select(t => Activator.CreateInstance(t) as ICommand) - .ToList(); + .Where(t => t.GetInterfaces().Contains(typeof(T)) && t.GetConstructor(Type.EmptyTypes) != null) + .Select(t => Activator.CreateInstance(t) as T) + .ToList()!; + } + + static MaintenanceHelper() + { + Commands = getListOfInterfaceObjects(); + MaintenanceJobs = getListOfInterfaceObjects(); } public static async Task RunCommand(string[] args) @@ -46,5 +55,18 @@ namespace LBPUnion.ProjectLighthouse.Helpers Console.WriteLine("Command not found."); } + + public static async Task RunMaintenanceJob(string jobName) + { + IMaintenanceJob? job = MaintenanceJobs.FirstOrDefault(j => j.GetType().Name == jobName); + if (job == null) throw new ArgumentNullException(); + + await RunMaintenanceJob(job); + } + + public static async Task RunMaintenanceJob(IMaintenanceJob job) + { + await job.Run(); + } } } \ No newline at end of file diff --git a/ProjectLighthouse/CommandLine/MakeUserAdminCommand.cs b/ProjectLighthouse/Maintenance/Commands/MakeUserAdminCommand.cs similarity index 92% rename from ProjectLighthouse/CommandLine/MakeUserAdminCommand.cs rename to ProjectLighthouse/Maintenance/Commands/MakeUserAdminCommand.cs index d96aaf99..4f0b0cbf 100644 --- a/ProjectLighthouse/CommandLine/MakeUserAdminCommand.cs +++ b/ProjectLighthouse/Maintenance/Commands/MakeUserAdminCommand.cs @@ -1,11 +1,13 @@ #nullable enable using System; using System.Threading.Tasks; +using JetBrains.Annotations; using LBPUnion.ProjectLighthouse.Types; using Microsoft.EntityFrameworkCore; -namespace LBPUnion.ProjectLighthouse.CommandLine +namespace LBPUnion.ProjectLighthouse.Maintenance.Commands { + [UsedImplicitly] public class MakeUserAdminCommand : ICommand { private readonly Database database = new(); diff --git a/ProjectLighthouse/CommandLine/ResetPasswordCommand.cs b/ProjectLighthouse/Maintenance/Commands/ResetPasswordCommand.cs similarity index 93% rename from ProjectLighthouse/CommandLine/ResetPasswordCommand.cs rename to ProjectLighthouse/Maintenance/Commands/ResetPasswordCommand.cs index a867c8d2..ed396765 100644 --- a/ProjectLighthouse/CommandLine/ResetPasswordCommand.cs +++ b/ProjectLighthouse/Maintenance/Commands/ResetPasswordCommand.cs @@ -1,12 +1,14 @@ #nullable enable using System; using System.Threading.Tasks; +using JetBrains.Annotations; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Types; using Microsoft.EntityFrameworkCore; -namespace LBPUnion.ProjectLighthouse.CommandLine +namespace LBPUnion.ProjectLighthouse.Maintenance.Commands { + [UsedImplicitly] public class ResetPasswordCommand : ICommand { private readonly Database database = new(); diff --git a/ProjectLighthouse/CommandLine/ICommand.cs b/ProjectLighthouse/Maintenance/ICommand.cs similarity index 86% rename from ProjectLighthouse/CommandLine/ICommand.cs rename to ProjectLighthouse/Maintenance/ICommand.cs index 263dd02f..3680fcf9 100644 --- a/ProjectLighthouse/CommandLine/ICommand.cs +++ b/ProjectLighthouse/Maintenance/ICommand.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace LBPUnion.ProjectLighthouse.CommandLine +namespace LBPUnion.ProjectLighthouse.Maintenance { public interface ICommand { diff --git a/ProjectLighthouse/Maintenance/IMaintenanceJob.cs b/ProjectLighthouse/Maintenance/IMaintenanceJob.cs new file mode 100644 index 00000000..4abd1dcb --- /dev/null +++ b/ProjectLighthouse/Maintenance/IMaintenanceJob.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; + +namespace LBPUnion.ProjectLighthouse.Maintenance +{ + public interface IMaintenanceJob + { + public Task Run(); + + public string Name(); + + public string Description(); + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Maintenance/MaintenanceJobs/CleanupBrokenPhotosMaintenanceJob.cs b/ProjectLighthouse/Maintenance/MaintenanceJobs/CleanupBrokenPhotosMaintenanceJob.cs new file mode 100644 index 00000000..9dde4d9f --- /dev/null +++ b/ProjectLighthouse/Maintenance/MaintenanceJobs/CleanupBrokenPhotosMaintenanceJob.cs @@ -0,0 +1,41 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Types; + +namespace LBPUnion.ProjectLighthouse.Maintenance.MaintenanceJobs +{ + public class CleanupBrokenPhotosMaintenanceJob : IMaintenanceJob + { + private readonly Database database = new(); + public string Name() => "Cleanup Broken Photos"; + public string Description() => "Deletes all photos that have missing assets."; + + [SuppressMessage("ReSharper", "LoopCanBePartlyConvertedToQuery")] + public async Task Run() + { + foreach (Photo photo in this.database.Photos) + { + bool hashNullOrEmpty = string.IsNullOrEmpty + (photo.LargeHash) || + string.IsNullOrEmpty(photo.MediumHash) || + string.IsNullOrEmpty(photo.SmallHash) || + string.IsNullOrEmpty(photo.PlanHash); + + bool allHashesDontExist = FileHelper.ResourcesNotUploaded(photo.LargeHash, photo.MediumHash, photo.SmallHash, photo.PlanHash).Length != 0; + + if (hashNullOrEmpty || allHashesDontExist) + { + Console.WriteLine + ( + $"Removing photo (id: {photo.PhotoId}): {nameof(hashNullOrEmpty)}: {hashNullOrEmpty}, {nameof(allHashesDontExist)}: {allHashesDontExist}" + ); + this.database.Photos.Remove(photo); + } + } + + await this.database.SaveChangesAsync(); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/AdminPanelPage.cshtml b/ProjectLighthouse/Pages/AdminPanelPage.cshtml index ea725c83..f9c92c5c 100644 --- a/ProjectLighthouse/Pages/AdminPanelPage.cshtml +++ b/ProjectLighthouse/Pages/AdminPanelPage.cshtml @@ -1,5 +1,6 @@ @page "/admin" -@using LBPUnion.ProjectLighthouse.CommandLine +@using LBPUnion.ProjectLighthouse.Helpers +@using LBPUnion.ProjectLighthouse.Maintenance @model LBPUnion.ProjectLighthouse.Pages.AdminPanelPage @{ @@ -8,11 +9,12 @@

Admin Panel

+

Commands

- @foreach (ICommand command in Model!.Commands) + @foreach (ICommand command in MaintenanceHelper.Commands) {
-
+

@command.Name()

@@ -27,4 +29,27 @@
} +
+

Maintenance Jobs

+

+ Warning: Interrupting Lighthouse during maintenance may leave the database in an unclean state. +

+ +
+ @foreach (IMaintenanceJob job in MaintenanceHelper.MaintenanceJobs) + { +
+
+

@job.Name()

+

@job.Description()

+ + + + +
+
+ }
\ No newline at end of file diff --git a/ProjectLighthouse/Pages/AdminPanelPage.cshtml.cs b/ProjectLighthouse/Pages/AdminPanelPage.cshtml.cs index 6101a981..ab4dbe61 100644 --- a/ProjectLighthouse/Pages/AdminPanelPage.cshtml.cs +++ b/ProjectLighthouse/Pages/AdminPanelPage.cshtml.cs @@ -1,8 +1,8 @@ #nullable enable using System.Collections.Generic; using System.Threading.Tasks; -using LBPUnion.ProjectLighthouse.CommandLine; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Maintenance; using LBPUnion.ProjectLighthouse.Pages.Layouts; using LBPUnion.ProjectLighthouse.Types; using Microsoft.AspNetCore.Mvc; @@ -14,9 +14,9 @@ namespace LBPUnion.ProjectLighthouse.Pages public AdminPanelPage(Database database) : base(database) {} - public List Commands = CommandHelper.Commands; + public List Commands = MaintenanceHelper.Commands; - public async Task OnGet([FromQuery] string? args, [FromQuery] string? command) + public async Task OnGet([FromQuery] string? args, [FromQuery] string? command, [FromQuery] string? maintenanceJob) { User? user = this.Database.UserFromWebRequest(this.Request); if (user == null) return this.Redirect("~/login"); @@ -27,7 +27,13 @@ namespace LBPUnion.ProjectLighthouse.Pages args ??= ""; args = command + " " + args; string[] split = args.Split(" "); - await CommandHelper.RunCommand(split); + await MaintenanceHelper.RunCommand(split); + return this.Redirect("~/admin"); + } + + if (!string.IsNullOrEmpty(maintenanceJob)) + { + await MaintenanceHelper.RunMaintenanceJob(maintenanceJob); return this.Redirect("~/admin"); } diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index 42af9ac9..1ef82df1 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -65,7 +65,7 @@ namespace LBPUnion.ProjectLighthouse if (args.Length != 0) { - CommandHelper.RunCommand(args).Wait(); + MaintenanceHelper.RunCommand(args).Wait(); return; } diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index a4e601cc..72508e66 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -33,6 +33,10 @@ + + + +