Add tool to delete orphaned files
parent
835a013bad
commit
38142c9129
|
@ -0,0 +1,9 @@
|
||||||
|
namespace LANCommander.Models
|
||||||
|
{
|
||||||
|
public class OrphanedFile
|
||||||
|
{
|
||||||
|
public string Path { get; set; }
|
||||||
|
public long Size { get; set; }
|
||||||
|
public DateTime CreatedOn { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
@page "/Settings/Tools/OrphanedFiles"
|
||||||
|
@using LANCommander.Helpers;
|
||||||
|
@using LANCommander.Models;
|
||||||
|
@layout SettingsLayout
|
||||||
|
@inject ArchiveService ArchiveService;
|
||||||
|
|
||||||
|
<PageHeader Title="Orphaned Files" />
|
||||||
|
|
||||||
|
<div style="padding: 0 24px;">
|
||||||
|
<p>
|
||||||
|
These files exist on the server, but aren't linked in the database. Use this tool to identify and delete orphaned files.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Table TItem="OrphanedFile" DataSource="@Orphans" Loading="@Loading" PageSize="25">
|
||||||
|
<PropertyColumn Property="f => f.Path" />
|
||||||
|
<PropertyColumn Property="f => f.Size" Sortable>
|
||||||
|
@ByteSizeLib.ByteSize.FromBytes(context.Size).ToString()
|
||||||
|
</PropertyColumn>
|
||||||
|
<PropertyColumn Property="f => f.CreatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable />
|
||||||
|
<ActionColumn Title="" Style="text-align: right">
|
||||||
|
<Space Direction="DirectionVHType.Horizontal">
|
||||||
|
<SpaceItem>
|
||||||
|
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this file?">
|
||||||
|
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
|
||||||
|
</Popconfirm>
|
||||||
|
</SpaceItem>
|
||||||
|
</Space>
|
||||||
|
</ActionColumn>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
ICollection<OrphanedFile> Orphans = new List<OrphanedFile>();
|
||||||
|
bool Loading = true;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
await LoadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task LoadData()
|
||||||
|
{
|
||||||
|
Loading = true;
|
||||||
|
|
||||||
|
Orphans = new List<OrphanedFile>();
|
||||||
|
|
||||||
|
var archives = await ArchiveService.Get();
|
||||||
|
var archiveFiles = archives.Select(a => ArchiveService.GetArchiveFileLocation(a));
|
||||||
|
var files = Directory.GetFiles("Upload");
|
||||||
|
|
||||||
|
foreach (var file in files.Where(f => !archiveFiles.Contains(f)))
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(file);
|
||||||
|
|
||||||
|
Orphans.Add(new OrphanedFile
|
||||||
|
{
|
||||||
|
Path = file,
|
||||||
|
Size = fileInfo.Length,
|
||||||
|
CreatedOn = fileInfo.CreationTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Orphans = Orphans.OrderByDescending(f => f.Size).ToList();
|
||||||
|
|
||||||
|
Loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task Delete(OrphanedFile file)
|
||||||
|
{
|
||||||
|
FileHelpers.DeleteIfExists(file.Path);
|
||||||
|
|
||||||
|
Orphans.Remove(file);
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,12 @@
|
||||||
<h3>Missing Archives</h3>
|
<h3>Missing Archives</h3>
|
||||||
<p>List and fix all archives that are missing their backing files.</p>
|
<p>List and fix all archives that are missing their backing files.</p>
|
||||||
<a href="/Settings/Tools/MissingArchives" class="ant-btn ant-btn-primary">View Missing Archives</a>
|
<a href="/Settings/Tools/MissingArchives" class="ant-btn ant-btn-primary">View Missing Archives</a>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<h3>Orphaned Files</h3>
|
||||||
|
<p>Find and delete any files that don't exist in the database and may be taking up unnecessary disk space.</p>
|
||||||
|
<a href="/Settings/Tools/OrphanedFiles" class="ant-btn ant-btn-primary">View Orphaned Files</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,20 @@ namespace LANCommander.Services
|
||||||
{
|
{
|
||||||
public class GameService : BaseDatabaseService<Game>
|
public class GameService : BaseDatabaseService<Game>
|
||||||
{
|
{
|
||||||
public GameService(DatabaseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
|
private readonly ArchiveService ArchiveService;
|
||||||
|
|
||||||
|
public GameService(DatabaseContext dbContext, IHttpContextAccessor httpContextAccessor, ArchiveService archiveService) : base(dbContext, httpContextAccessor)
|
||||||
{
|
{
|
||||||
|
ArchiveService = archiveService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Delete(Game game)
|
public override async Task Delete(Game game)
|
||||||
{
|
{
|
||||||
foreach (var archive in game.Archives.OrderByDescending(a => a.CreatedOn))
|
foreach (var archive in game.Archives.OrderByDescending(a => a.CreatedOn))
|
||||||
{
|
{
|
||||||
|
await ArchiveService.Delete(archive);
|
||||||
|
|
||||||
FileHelpers.DeleteIfExists($"Icon/{game.Id}.png".ToPath());
|
FileHelpers.DeleteIfExists($"Icon/{game.Id}.png".ToPath());
|
||||||
FileHelpers.DeleteIfExists($"Upload/{archive.ObjectKey}".ToPath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await base.Delete(game);
|
await base.Delete(game);
|
||||||
|
|
Loading…
Reference in New Issue