🐛 Try to fix the soft delete filter didn't work in drive

This commit is contained in:
2025-11-17 23:19:03 +08:00
parent a172128d84
commit 4280168002
5 changed files with 38 additions and 24 deletions

View File

@@ -48,27 +48,33 @@ public class AppDatabase(
base.OnModelCreating(modelBuilder); base.OnModelCreating(modelBuilder);
// Apply soft-delete filter only to root entities, not derived types // Apply soft-delete filter only to root entities, not derived types
foreach (var entityType in modelBuilder.Model.GetEntityTypes()) var entityTypes = modelBuilder.Model.GetEntityTypes();
foreach (var entityType in entityTypes)
{ {
if (!typeof(ModelBase).IsAssignableFrom(entityType.ClrType)) continue; if (!typeof(ModelBase).IsAssignableFrom(entityType.ClrType)) continue;
// Skip derived types to avoid filter conflicts // Skip derived types to avoid filter conflicts
var clrType = entityType.ClrType; var clrType = entityType.ClrType;
if (clrType.BaseType != typeof(object) && if (clrType.BaseType != typeof(ModelBase) &&
typeof(ModelBase).IsAssignableFrom(clrType.BaseType)) typeof(ModelBase).IsAssignableFrom(clrType.BaseType))
{ {
continue; // Skip derived types continue; // Skip derived types
} }
var method = typeof(AppDatabase) // Apply soft delete filter using cached reflection
.GetMethod(nameof(SetSoftDeleteFilter), ApplySoftDeleteFilter(modelBuilder, clrType);
BindingFlags.NonPublic | BindingFlags.Static)!
.MakeGenericMethod(clrType);
method.Invoke(null, [modelBuilder]);
} }
} }
private static readonly MethodInfo SetSoftDeleteFilterMethod = typeof(AppDatabase)
.GetMethod(nameof(SetSoftDeleteFilter), BindingFlags.NonPublic | BindingFlags.Static)!;
private static void ApplySoftDeleteFilter(ModelBuilder modelBuilder, Type entityType)
{
var genericMethod = SetSoftDeleteFilterMethod.MakeGenericMethod(entityType);
genericMethod.Invoke(null, [modelBuilder]);
}
private static void SetSoftDeleteFilter<TEntity>(ModelBuilder modelBuilder) private static void SetSoftDeleteFilter<TEntity>(ModelBuilder modelBuilder)
where TEntity : ModelBase where TEntity : ModelBase
{ {

View File

@@ -157,7 +157,8 @@ public class FileIndexController(
var query = db.Files var query = db.Files
.Where(f => f.AccountId == accountId .Where(f => f.AccountId == accountId
&& f.IsMarkedRecycle == recycled && f.IsMarkedRecycle == recycled
&& !db.FileIndexes.Any(fi => fi.FileId == f.Id && fi.AccountId == accountId)) && !db.FileIndexes.Any(fi => fi.FileId == f.Id && fi.AccountId == accountId)
)
.OrderByDescending(f => f.CreatedAt) .OrderByDescending(f => f.CreatedAt)
.AsQueryable(); .AsQueryable();
@@ -509,4 +510,4 @@ public class CreateFileIndexRequest
{ {
[MaxLength(32)] public string FileId { get; set; } = null!; [MaxLength(32)] public string FileId { get; set; } = null!;
public string Path { get; set; } = null!; public string Path { get; set; } = null!;
} }

View File

@@ -306,7 +306,7 @@ public class FileController(
[Authorize] [Authorize]
[HttpDelete("{id}")] [HttpDelete("{id}")]
public async Task<ActionResult> DeleteFile(string id) public async Task<ActionResult<SnCloudFile>> DeleteFile(string id)
{ {
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
var userId = Guid.Parse(currentUser.Id); var userId = Guid.Parse(currentUser.Id);
@@ -318,9 +318,9 @@ public class FileController(
if (file is null) return NotFound(); if (file is null) return NotFound();
await fs.DeleteFileDataAsync(file, force: true); await fs.DeleteFileDataAsync(file, force: true);
await fs.DeleteFileAsync(file); await fs.DeleteFileAsync(file, skipData: true);
return NoContent(); return Ok(file);
} }
[Authorize] [Authorize]

View File

@@ -103,7 +103,8 @@ public class FileService(
var bundle = await ValidateAndGetBundleAsync(fileBundleId, accountId); var bundle = await ValidateAndGetBundleAsync(fileBundleId, accountId);
var finalExpiredAt = CalculateFinalExpiration(expiredAt, pool, bundle); var finalExpiredAt = CalculateFinalExpiration(expiredAt, pool, bundle);
var (managedTempPath, fileSize, finalContentType) = await PrepareFileAsync(fileId, filePath, fileName, contentType); var (managedTempPath, fileSize, finalContentType) =
await PrepareFileAsync(fileId, filePath, fileName, contentType);
var file = CreateFileObject(fileId, fileName, finalContentType, fileSize, finalExpiredAt, bundle, accountId); var file = CreateFileObject(fileId, fileName, finalContentType, fileSize, finalExpiredAt, bundle, accountId);
@@ -112,7 +113,8 @@ public class FileService(
await ExtractMetadataAsync(file, managedTempPath); await ExtractMetadataAsync(file, managedTempPath);
} }
var (processingPath, isTempFile) = await ProcessEncryptionAsync(fileId, managedTempPath, encryptPassword, pool, file); var (processingPath, isTempFile) =
await ProcessEncryptionAsync(fileId, managedTempPath, encryptPassword, pool, file);
file.Hash = await HashFileAsync(processingPath); file.Hash = await HashFileAsync(processingPath);
@@ -231,7 +233,8 @@ public class FileService(
file.StorageId ??= file.Id; file.StorageId ??= file.Id;
} }
private async Task PublishFileUploadedEventAsync(SnCloudFile file, FilePool pool, string processingPath, bool isTempFile) private async Task PublishFileUploadedEventAsync(SnCloudFile file, FilePool pool, string processingPath,
bool isTempFile)
{ {
var js = nats.CreateJetStreamContext(); var js = nats.CreateJetStreamContext();
await js.PublishAsync( await js.PublishAsync(
@@ -471,13 +474,14 @@ public class FileService(
return await db.Files.AsNoTracking().FirstAsync(f => f.Id == file.Id); return await db.Files.AsNoTracking().FirstAsync(f => f.Id == file.Id);
} }
public async Task DeleteFileAsync(SnCloudFile file) public async Task DeleteFileAsync(SnCloudFile file, bool skipData = false)
{ {
db.Remove(file); db.Remove(file);
await db.SaveChangesAsync(); await db.SaveChangesAsync();
await _PurgeCacheAsync(file.Id); await _PurgeCacheAsync(file.Id);
await DeleteFileDataAsync(file); if (!skipData)
await DeleteFileDataAsync(file);
} }
public async Task DeleteFileDataAsync(SnCloudFile file, bool force = false) public async Task DeleteFileDataAsync(SnCloudFile file, bool force = false)
@@ -660,9 +664,12 @@ public class FileService(
} }
} }
return [.. references return
.Select(r => cachedFiles.GetValueOrDefault(r.Id)) [
.Where(f => f != null)]; .. references
.Select(r => cachedFiles.GetValueOrDefault(r.Id))
.Where(f => f != null)
];
} }
public async Task<int> GetReferenceCountAsync(string fileId) public async Task<int> GetReferenceCountAsync(string fileId)
@@ -781,4 +788,4 @@ file class UpdatableCloudFile(SnCloudFile file)
.SetProperty(f => f.UserMeta, userMeta) .SetProperty(f => f.UserMeta, userMeta)
.SetProperty(f => f.IsMarkedRecycle, IsMarkedRecycle); .SetProperty(f => f.IsMarkedRecycle, IsMarkedRecycle);
} }
} }

View File

@@ -86,9 +86,9 @@ public class SnCloudFile : ModelBase, ICloudFile, IIdentifiedResource
/// Converts the CloudFile to a protobuf message /// Converts the CloudFile to a protobuf message
/// </summary> /// </summary>
/// <returns>The protobuf message representation of this object</returns> /// <returns>The protobuf message representation of this object</returns>
public Proto.CloudFile ToProtoValue() public CloudFile ToProtoValue()
{ {
var proto = new Proto.CloudFile var proto = new CloudFile
{ {
Id = Id, Id = Id,
Name = Name, Name = Name,