Add tool to delete orphaned files
This commit is contained in:
		
							parent
							
								
									835a013bad
								
							
						
					
					
						commit
						38142c9129
					
				
					 4 changed files with 97 additions and 2 deletions
				
			
		
							
								
								
									
										9
									
								
								LANCommander/Models/OrphanedFile.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								LANCommander/Models/OrphanedFile.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								LANCommander/Pages/Settings/Tools/OrphanedFiles.razor
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								LANCommander/Pages/Settings/Tools/OrphanedFiles.razor
									
										
									
									
									
										Normal file
									
								
							|  | @ -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…
	
	Add table
		
		Reference in a new issue
	
	 Pat Hartl
						Pat Hartl