Dosya Yöneticis kısmında iç içe klasörler

This commit is contained in:
Sedat Öztürk 2025-10-26 12:27:06 +03:00
parent f839d1fec0
commit 79bd897a0b
2 changed files with 62 additions and 60 deletions

View file

@ -48,6 +48,18 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
return Guid.NewGuid().ToString("N"); return Guid.NewGuid().ToString("N");
} }
private string EncodePathAsId(string path)
{
// Path'deki '/' karakterlerini '|' ile değiştir URL-safe hale getirmek için
return path.Replace("/", "|");
}
private string DecodeIdAsPath(string id)
{
// ID'deki '|' karakterlerini '/' ile geri değiştir
return id.Replace("|", "/");
}
private async Task<List<FileMetadata>> GetFolderIndexAsync(string? parentId = null) private async Task<List<FileMetadata>> GetFolderIndexAsync(string? parentId = null)
{ {
return await GetRealCdnContentsAsync(parentId); return await GetRealCdnContentsAsync(parentId);
@ -89,7 +101,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
items.Add(new FileMetadata items.Add(new FileMetadata
{ {
Id = relativePath, Id = EncodePathAsId(relativePath),
Name = dirInfo.Name, Name = dirInfo.Name,
Type = "folder", Type = "folder",
CreatedAt = dirInfo.CreationTime, CreatedAt = dirInfo.CreationTime,
@ -110,7 +122,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
items.Add(new FileMetadata items.Add(new FileMetadata
{ {
Id = relativePath, Id = EncodePathAsId(relativePath),
Name = fileInfo.Name, Name = fileInfo.Name,
Type = "file", Type = "file",
Size = fileInfo.Length, Size = fileInfo.Length,
@ -170,7 +182,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
public async Task<GetFilesDto> GetItemsByParentAsync(string parentId) public async Task<GetFilesDto> GetItemsByParentAsync(string parentId)
{ {
return await GetItemsInternalAsync(parentId); var decodedParentId = DecodeIdAsPath(parentId);
return await GetItemsInternalAsync(decodedParentId);
} }
private async Task<GetFilesDto> GetItemsInternalAsync(string? parentId) private async Task<GetFilesDto> GetItemsInternalAsync(string? parentId)
@ -208,9 +221,11 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
var tenantId = _currentTenant.Id?.ToString() ?? "host"; var tenantId = _currentTenant.Id?.ToString() ?? "host";
var parentPath = Path.Combine(cdnBasePath, tenantId); var parentPath = Path.Combine(cdnBasePath, tenantId);
string? decodedParentId = null;
if (!string.IsNullOrEmpty(input.ParentId)) if (!string.IsNullOrEmpty(input.ParentId))
{ {
parentPath = Path.Combine(parentPath, input.ParentId); decodedParentId = DecodeIdAsPath(input.ParentId);
parentPath = Path.Combine(parentPath, decodedParentId);
} }
var folderPath = Path.Combine(parentPath, input.Name); var folderPath = Path.Combine(parentPath, input.Name);
@ -230,15 +245,17 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
// Klasörü oluştur // Klasörü oluştur
Directory.CreateDirectory(folderPath); Directory.CreateDirectory(folderPath);
var newFolderPath = string.IsNullOrEmpty(decodedParentId) ? input.Name : $"{decodedParentId}/{input.Name}";
var metadata = new FileMetadata var metadata = new FileMetadata
{ {
Id = string.IsNullOrEmpty(input.ParentId) ? input.Name : $"{input.ParentId}/{input.Name}", Id = EncodePathAsId(newFolderPath),
Name = input.Name, Name = input.Name,
Type = "folder", Type = "folder",
CreatedAt = DateTime.UtcNow, CreatedAt = DateTime.UtcNow,
ModifiedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow,
Path = string.IsNullOrEmpty(input.ParentId) ? input.Name : $"{input.ParentId}/{input.Name}", Path = newFolderPath,
ParentId = input.ParentId ?? string.Empty, ParentId = decodedParentId ?? string.Empty,
IsReadOnly = false, IsReadOnly = false,
TenantId = _currentTenant.Id?.ToString() TenantId = _currentTenant.Id?.ToString()
}; };
@ -260,19 +277,25 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
{ {
ValidateFileName(input.FileName); ValidateFileName(input.FileName);
var items = await GetFolderIndexAsync(input.ParentId); // Decode parent ID if provided
string? decodedParentId = null;
if (!string.IsNullOrEmpty(input.ParentId))
{
decodedParentId = DecodeIdAsPath(input.ParentId);
}
var items = await GetFolderIndexAsync(decodedParentId);
if (items.Any(x => x.Name.Equals(input.FileName, StringComparison.OrdinalIgnoreCase))) if (items.Any(x => x.Name.Equals(input.FileName, StringComparison.OrdinalIgnoreCase)))
{ {
throw new UserFriendlyException("A file with this name already exists"); throw new UserFriendlyException("A file with this name already exists");
} }
var fileId = GenerateFileId(); var filePath = string.IsNullOrEmpty(decodedParentId)
var filePath = string.IsNullOrEmpty(input.ParentId)
? input.FileName ? input.FileName
: $"{input.ParentId}/{input.FileName}"; : $"{decodedParentId}/{input.FileName}";
var blobPath = GetTenantPrefix() + filePath; var fileId = EncodePathAsId(filePath);
// Save file content to CDN path // Save file content to CDN path
var cdnBasePath = _configuration["App:CdnPath"]; var cdnBasePath = _configuration["App:CdnPath"];
@ -284,9 +307,9 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
var tenantId = _currentTenant.Id?.ToString() ?? "host"; var tenantId = _currentTenant.Id?.ToString() ?? "host";
var fullCdnPath = Path.Combine(cdnBasePath, tenantId); var fullCdnPath = Path.Combine(cdnBasePath, tenantId);
if (!string.IsNullOrEmpty(input.ParentId)) if (!string.IsNullOrEmpty(decodedParentId))
{ {
fullCdnPath = Path.Combine(fullCdnPath, input.ParentId); fullCdnPath = Path.Combine(fullCdnPath, decodedParentId);
} }
// Dizini oluştur // Dizini oluştur
@ -325,14 +348,12 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
CreatedAt = DateTime.UtcNow, CreatedAt = DateTime.UtcNow,
ModifiedAt = DateTime.UtcNow, ModifiedAt = DateTime.UtcNow,
Path = filePath, Path = filePath,
ParentId = input.ParentId ?? string.Empty, ParentId = decodedParentId ?? string.Empty,
IsReadOnly = false, IsReadOnly = false,
TenantId = _currentTenant.Id?.ToString() TenantId = _currentTenant.Id?.ToString()
}; };
// Update parent index // File system'e kaydedildi, index güncellemeye gerek yok
items.Add(metadata);
await SaveFolderIndexAsync(items, input.ParentId);
return new FileItemDto return new FileItemDto
{ {
@ -485,7 +506,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
} }
var tenantId = _currentTenant.Id?.ToString() ?? "host"; var tenantId = _currentTenant.Id?.ToString() ?? "host";
var fullPath = Path.Combine(cdnBasePath, tenantId, id); var actualPath = DecodeIdAsPath(id);
var fullPath = Path.Combine(cdnBasePath, tenantId, actualPath);
if (Directory.Exists(fullPath)) if (Directory.Exists(fullPath))
{ {
@ -512,7 +534,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
} }
var tenantId = _currentTenant.Id?.ToString() ?? "host"; var tenantId = _currentTenant.Id?.ToString() ?? "host";
var fullFilePath = Path.Combine(cdnBasePath, tenantId, id); var actualPath = DecodeIdAsPath(id);
var fullFilePath = Path.Combine(cdnBasePath, tenantId, actualPath);
if (!File.Exists(fullFilePath)) if (!File.Exists(fullFilePath))
{ {
@ -557,38 +580,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
public async Task<FolderPathDto> GetFolderPathAsync(string? folderId = null) public async Task<FolderPathDto> GetFolderPathAsync(string? folderId = null)
{ {
var path = new List<PathItemDto>(); return await GetFolderPathInternalAsync(folderId);
if (string.IsNullOrEmpty(folderId))
{
return new FolderPathDto { Path = path };
}
var metadata = await FindItemMetadataAsync(folderId);
if (metadata == null || metadata.Type != "folder")
{
throw new UserFriendlyException("Folder not found");
}
var pathParts = metadata.Path.Split('/', StringSplitOptions.RemoveEmptyEntries);
var currentPath = "";
foreach (var part in pathParts)
{
currentPath = string.IsNullOrEmpty(currentPath) ? part : $"{currentPath}/{part}";
var folderMetadata = await FindItemByPathAsync(currentPath);
if (folderMetadata != null)
{
path.Add(new PathItemDto
{
Id = folderMetadata.Id,
Name = folderMetadata.Name
});
}
}
return new FolderPathDto { Path = path };
} }
#region Private Helper Methods #region Private Helper Methods
@ -698,21 +690,30 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
return new FolderPathDto { Path = pathItems }; return new FolderPathDto { Path = pathItems };
} }
// Reconstruct path from folderId // Decode the folderId to get the actual path
var currentPath = folderId; var decodedPath = DecodeIdAsPath(folderId);
var pathParts = currentPath.Split('/', StringSplitOptions.RemoveEmptyEntries); Logger.LogInformation($"GetFolderPath - FolderId: {folderId}, DecodedPath: {decodedPath}");
var reconstructedPath = ""; // Split path into parts and build breadcrumb
foreach (var part in pathParts) var pathParts = decodedPath.Split('/', StringSplitOptions.RemoveEmptyEntries);
var currentEncodedPath = "";
for (int i = 0; i < pathParts.Length; i++)
{ {
reconstructedPath = string.IsNullOrEmpty(reconstructedPath) ? part : $"{reconstructedPath}/{part}"; // Build the path up to current level
var pathUpToCurrent = string.Join("/", pathParts.Take(i + 1));
currentEncodedPath = EncodePathAsId(pathUpToCurrent);
Logger.LogInformation($"PathItem {i}: Name='{pathParts[i]}', Id='{currentEncodedPath}', PathUpToCurrent='{pathUpToCurrent}'");
pathItems.Add(new PathItemDto pathItems.Add(new PathItemDto
{ {
Id = reconstructedPath, Id = currentEncodedPath,
Name = part Name = pathParts[i] // Use the actual folder name, not encoded path
}); });
} }
Logger.LogInformation($"Returning {pathItems.Count} breadcrumb items");
return new FolderPathDto { Path = pathItems }; return new FolderPathDto { Path = pathItems };
} }

View file

@ -78,6 +78,7 @@ const FileManager = () => {
} }
const response = await fileManagementService.getFolderPath(folderId) const response = await fileManagementService.getFolderPath(folderId)
console.log('Breadcrumb response for folderId:', folderId, response)
const pathItems: BreadcrumbItem[] = [ const pathItems: BreadcrumbItem[] = [
{ name: 'Files', path: '', id: undefined }, { name: 'Files', path: '', id: undefined },
...response.data.path.map((item) => ({ ...response.data.path.map((item) => ({