FileManager IsProtectedFolder düzenlemesi
This commit is contained in:
parent
771ea95e55
commit
fc30539916
8 changed files with 103 additions and 117 deletions
|
|
@ -16,6 +16,7 @@ public class FileItemDto
|
|||
public string Path { get; set; } = string.Empty;
|
||||
public string ParentId { get; set; } = string.Empty;
|
||||
public bool IsReadOnly { get; set; }
|
||||
public bool IsProtectedFolder { get; set; }
|
||||
public int? ChildCount { get; set; }
|
||||
public string TenantId { get; set; } = string.Empty;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
private const string FolderMarkerSuffix = ".folder";
|
||||
private const string IndexFileName = "index.json";
|
||||
|
||||
// Protected system folders that cannot be deleted, renamed, or moved
|
||||
private static readonly HashSet<string> ProtectedFolders = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
// BlobContainerNames.Avatar,
|
||||
// BlobContainerNames.Import,
|
||||
// BlobContainerNames.Note,
|
||||
// BlobContainerNames.Intranet
|
||||
// BlobContainerNames.Backup
|
||||
BlobContainerNames.Intranet,
|
||||
BlobContainerNames.Avatar,
|
||||
BlobContainerNames.Import,
|
||||
BlobContainerNames.Messenger,
|
||||
BlobContainerNames.Note,
|
||||
BlobContainerNames.Backup
|
||||
};
|
||||
|
||||
public FileManagementAppService(
|
||||
|
|
@ -122,6 +122,39 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
return isProtected;
|
||||
}
|
||||
|
||||
private bool IsProtectedRootFolder(string path)
|
||||
{
|
||||
var pathParts = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
return pathParts.Length == 1 && ProtectedFolders.Contains(pathParts[0]);
|
||||
}
|
||||
|
||||
private FileItemDto ToFileItemDto(
|
||||
FileMetadata metadata,
|
||||
string? parentId = null,
|
||||
string? tenantId = null)
|
||||
{
|
||||
var isProtectedFolder = metadata.Type == "folder" && IsProtectedRootFolder(metadata.Path);
|
||||
var isReadOnly = metadata.IsReadOnly || isProtectedFolder;
|
||||
|
||||
return new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
Name = metadata.Name,
|
||||
Type = metadata.Type,
|
||||
Size = metadata.Size,
|
||||
Extension = metadata.Extension,
|
||||
MimeType = metadata.MimeType,
|
||||
CreatedAt = metadata.CreatedAt,
|
||||
ModifiedAt = metadata.ModifiedAt,
|
||||
Path = metadata.Path,
|
||||
ParentId = parentId ?? metadata.ParentId,
|
||||
IsReadOnly = isReadOnly,
|
||||
IsProtectedFolder = isProtectedFolder,
|
||||
ChildCount = metadata.ChildCount,
|
||||
TenantId = tenantId == "host" ? null : (tenantId ?? metadata.TenantId)
|
||||
};
|
||||
}
|
||||
|
||||
private void ValidateNotProtectedFolder(string id, string operation)
|
||||
{
|
||||
var decodedPath = DecodeIdAsPath(id);
|
||||
|
|
@ -267,29 +300,11 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
var items = await GetFolderIndexAsync(parentId, tenantId);
|
||||
|
||||
var result = items.Select(metadata =>
|
||||
{
|
||||
var isRootLevel = string.IsNullOrEmpty(parentId);
|
||||
var isProtected = IsProtectedFolder(metadata.Path);
|
||||
var finalIsReadOnly = metadata.IsReadOnly || (isRootLevel && isProtected);
|
||||
|
||||
return new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
Name = metadata.Name,
|
||||
Type = metadata.Type,
|
||||
Size = metadata.Size,
|
||||
Extension = metadata.Extension,
|
||||
MimeType = metadata.MimeType,
|
||||
CreatedAt = metadata.CreatedAt,
|
||||
ModifiedAt = metadata.ModifiedAt,
|
||||
Path = metadata.Path,
|
||||
ParentId = parentId ?? string.Empty,
|
||||
IsReadOnly = finalIsReadOnly,
|
||||
ChildCount = metadata.ChildCount,
|
||||
TenantId = metadata.TenantId
|
||||
};
|
||||
}).OrderBy(x => x.Type == "folder" ? 0 : 1).ThenBy(x => x.Name).ToList();
|
||||
var result = items
|
||||
.Select(metadata => ToFileItemDto(metadata, parentId ?? string.Empty))
|
||||
.OrderBy(x => x.Type == "folder" ? 0 : 1)
|
||||
.ThenBy(x => x.Name)
|
||||
.ToList();
|
||||
|
||||
return new GetFilesDto { Items = result };
|
||||
}
|
||||
|
|
@ -347,18 +362,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
TenantId = tenantId == "host" ? null : tenantId
|
||||
};
|
||||
|
||||
return new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
Name = metadata.Name,
|
||||
Type = metadata.Type,
|
||||
CreatedAt = metadata.CreatedAt,
|
||||
ModifiedAt = metadata.ModifiedAt,
|
||||
Path = metadata.Path,
|
||||
ParentId = input.ParentId ?? string.Empty,
|
||||
IsReadOnly = metadata.IsReadOnly,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
};
|
||||
return ToFileItemDto(metadata, input.ParentId ?? string.Empty, tenantId);
|
||||
}
|
||||
|
||||
[HttpPost("api/app/file-management/upload-file")]
|
||||
|
|
@ -440,21 +444,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
};
|
||||
|
||||
// File system'e kaydedildi, index güncellemeye gerek yok
|
||||
return new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
Name = metadata.Name,
|
||||
Type = metadata.Type,
|
||||
Size = metadata.Size,
|
||||
Extension = metadata.Extension,
|
||||
MimeType = metadata.MimeType,
|
||||
CreatedAt = metadata.CreatedAt,
|
||||
ModifiedAt = metadata.ModifiedAt,
|
||||
Path = metadata.Path,
|
||||
ParentId = input.ParentId ?? string.Empty,
|
||||
IsReadOnly = metadata.IsReadOnly,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
};
|
||||
return ToFileItemDto(metadata, input.ParentId ?? string.Empty, tenantId);
|
||||
}
|
||||
|
||||
[HttpPost("api/app/file-management/{id}/rename-item")]
|
||||
|
|
@ -511,21 +501,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
await SaveFolderIndexAsync(parentItems, tenantId, metadata.ParentId == string.Empty ? null : metadata.ParentId);
|
||||
|
||||
return new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
Name = metadata.Name,
|
||||
Type = metadata.Type,
|
||||
Size = metadata.Size,
|
||||
Extension = metadata.Extension,
|
||||
MimeType = metadata.MimeType,
|
||||
CreatedAt = metadata.CreatedAt,
|
||||
ModifiedAt = metadata.ModifiedAt,
|
||||
Path = metadata.Path,
|
||||
ParentId = metadata.ParentId,
|
||||
IsReadOnly = metadata.IsReadOnly,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
};
|
||||
return ToFileItemDto(metadata, metadata.ParentId, tenantId);
|
||||
}
|
||||
|
||||
[HttpPost("api/app/file-management/{id}/move-item")]
|
||||
|
|
@ -577,21 +553,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
targetItems.Add(metadata);
|
||||
await SaveFolderIndexAsync(targetItems, tenantId, input.TargetFolderId);
|
||||
|
||||
return new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
Name = metadata.Name,
|
||||
Type = metadata.Type,
|
||||
Size = metadata.Size,
|
||||
Extension = metadata.Extension,
|
||||
MimeType = metadata.MimeType,
|
||||
CreatedAt = metadata.CreatedAt,
|
||||
ModifiedAt = metadata.ModifiedAt,
|
||||
Path = metadata.Path,
|
||||
ParentId = metadata.ParentId,
|
||||
IsReadOnly = metadata.IsReadOnly,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
};
|
||||
return ToFileItemDto(metadata, metadata.ParentId, tenantId);
|
||||
}
|
||||
|
||||
[HttpDelete("api/app/file-management/{id}/item/{tenantId}")]
|
||||
|
|
@ -739,6 +701,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
Path = finalTargetPath,
|
||||
ParentId = input.TargetFolderId ?? string.Empty,
|
||||
IsReadOnly = false,
|
||||
IsProtectedFolder = false,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
});
|
||||
}
|
||||
|
|
@ -769,6 +732,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
Path = finalTargetPath,
|
||||
ParentId = input.TargetFolderId ?? string.Empty,
|
||||
IsReadOnly = false,
|
||||
IsProtectedFolder = false,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
});
|
||||
}
|
||||
|
|
@ -867,6 +831,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
Path = finalTargetPath,
|
||||
ParentId = input.TargetFolderId ?? string.Empty,
|
||||
IsReadOnly = false,
|
||||
IsProtectedFolder = false,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
});
|
||||
}
|
||||
|
|
@ -897,6 +862,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
Path = finalTargetPath,
|
||||
ParentId = input.TargetFolderId ?? string.Empty,
|
||||
IsReadOnly = false,
|
||||
IsProtectedFolder = false,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
});
|
||||
}
|
||||
|
|
@ -955,21 +921,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
var filteredItems = allItems
|
||||
.Where(x => x.Name.ToLowerInvariant().Contains(query))
|
||||
.Select(metadata => new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
Name = metadata.Name,
|
||||
Type = metadata.Type,
|
||||
Size = metadata.Size,
|
||||
Extension = metadata.Extension,
|
||||
MimeType = metadata.MimeType,
|
||||
CreatedAt = metadata.CreatedAt,
|
||||
ModifiedAt = metadata.ModifiedAt,
|
||||
Path = metadata.Path,
|
||||
ParentId = metadata.ParentId,
|
||||
IsReadOnly = metadata.IsReadOnly,
|
||||
TenantId = tenantId == "host" ? null : tenantId
|
||||
})
|
||||
.Select(metadata => ToFileItemDto(metadata, metadata.ParentId, tenantId))
|
||||
.OrderBy(x => x.Type == "folder" ? 0 : 1)
|
||||
.ThenBy(x => x.Name)
|
||||
.ToList();
|
||||
|
|
|
|||
|
|
@ -571,6 +571,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
Path = relativePath,
|
||||
ParentId = string.Empty,
|
||||
IsReadOnly = false,
|
||||
IsProtectedFolder = false,
|
||||
ChildCount = 0,
|
||||
TenantId = _currentTenant.Id?.ToString()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ using IdentityUser = Volo.Abp.Identity.IdentityUser;
|
|||
using Sozsoft.Platform.BlobStoring;
|
||||
using Sozsoft.Platform.Identity;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Sozsoft.Platform.ListForms.DynamicApi;
|
||||
|
||||
|
|
@ -32,6 +33,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
private readonly IdentityUserManager userManager;
|
||||
private readonly BlobManager blobCdnManager;
|
||||
private readonly IConfiguration configuration;
|
||||
private readonly IHostEnvironment hostEnvironment;
|
||||
private readonly IOptions<IdentityOptions> identityOptions;
|
||||
|
||||
public ListFormDynamicApiAppService(
|
||||
|
|
@ -42,6 +44,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
IdentityUserManager userManager,
|
||||
BlobManager blobCdnManager,
|
||||
IConfiguration configuration,
|
||||
IHostEnvironment hostEnvironment,
|
||||
IOptions<IdentityOptions> identityOptions)
|
||||
{
|
||||
this.tenantRepository = tenantRepository;
|
||||
|
|
@ -51,6 +54,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
this.userManager = userManager;
|
||||
this.blobCdnManager = blobCdnManager;
|
||||
this.configuration = configuration;
|
||||
this.hostEnvironment = hostEnvironment;
|
||||
this.identityOptions = identityOptions;
|
||||
}
|
||||
|
||||
|
|
@ -59,10 +63,15 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
return Guid.TryParse(value, out var id) ? id : Guid.Empty;
|
||||
}
|
||||
|
||||
private async Task SaveAvatarAsync(IdentityUser user, string avatar)
|
||||
private async Task SaveAvatarAsync(IdentityUser user, string avatar, bool saveDefaultWhenMissing = false)
|
||||
{
|
||||
if (avatar.IsNullOrWhiteSpace())
|
||||
{
|
||||
if (saveDefaultWhenMissing)
|
||||
{
|
||||
await SaveDefaultAvatarAsync(user);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -94,6 +103,38 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
user.SetAvatar(AvatarProvider.GetAvatar(configuration, user.TenantId?.ToString(), user.Id.ToString()));
|
||||
}
|
||||
|
||||
private async Task SaveDefaultAvatarAsync(IdentityUser user)
|
||||
{
|
||||
var defaultAvatarPath = FindDefaultAvatarPath();
|
||||
if (defaultAvatarPath == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var fileName = $"{user.Id}.jpg";
|
||||
await using var stream = File.OpenRead(defaultAvatarPath);
|
||||
await blobCdnManager.SaveAsync(BlobContainerNames.Avatar, fileName, stream);
|
||||
user.SetAvatar(AvatarProvider.GetAvatar(configuration, user.TenantId?.ToString(), user.Id.ToString()));
|
||||
}
|
||||
|
||||
private string? FindDefaultAvatarPath()
|
||||
{
|
||||
var directory = new DirectoryInfo(hostEnvironment.ContentRootPath);
|
||||
|
||||
while (directory != null)
|
||||
{
|
||||
var candidate = Path.Combine(directory.FullName, "ui", "public", "img", "others", "default-profile.png");
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[Authorize(IdentityPermissions.Users.Create)]
|
||||
public async Task PostUserInsertAsync(DynamicApiBaseInput<CreateUpdateUserInput> input)
|
||||
{
|
||||
|
|
@ -119,7 +160,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
user.SetJobPositionId(ParseGuid(input.Data.JobPositionId));
|
||||
user.SetIsVerified(verify);
|
||||
|
||||
await SaveAvatarAsync(user, input.Data.Avatar);
|
||||
await SaveAvatarAsync(user, input.Data.Avatar, saveDefaultWhenMissing: true);
|
||||
|
||||
(await userManager.CreateAsync(user, input.Data.Password)).CheckErrors();
|
||||
await userManager.SetLockoutEnabledAsync(user, true);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"commit": "7632c9e",
|
||||
"commit": "771ea95",
|
||||
"releases": [
|
||||
{
|
||||
"version": "1.1.04",
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export interface DocumentDto {
|
|||
path: string
|
||||
parentId: string
|
||||
isReadOnly: boolean
|
||||
isProtectedFolder: boolean
|
||||
childCount: number
|
||||
tenantId?: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export interface FileItem {
|
|||
path: string
|
||||
extension: string
|
||||
isReadOnly: boolean
|
||||
isProtectedFolder: boolean
|
||||
childCount?: number // Klasörler için öğe sayısı
|
||||
tenantId?: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,18 +136,7 @@ const FileManager = () => {
|
|||
const response = await fileManagementService.getItems(folderId, selectedTenant?.id)
|
||||
// Backend returns GetFilesDto which has Items property
|
||||
const items = response.data.items || []
|
||||
// Manual protection for system folders
|
||||
const protectedItems = items.map((item) => {
|
||||
const isSystemFolder = ['intranet', 'avatar', 'import', 'note', 'backup'].includes(
|
||||
item.name.toLowerCase(),
|
||||
)
|
||||
return {
|
||||
...item,
|
||||
isReadOnly: item.isReadOnly || isSystemFolder,
|
||||
}
|
||||
})
|
||||
|
||||
setItems(protectedItems)
|
||||
setItems(items)
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch items:', error)
|
||||
toast.push(<Notification type="danger">Failed to load files and folders</Notification>)
|
||||
|
|
|
|||
Loading…
Reference in a new issue