diff --git a/aspnet-core/modules/cloud-aliyun/LINGYUN.Abp.Aliyun/README.md b/aspnet-core/modules/cloud-aliyun/LINGYUN.Abp.Aliyun/README.md index 6cb396563..97c68d074 100644 --- a/aspnet-core/modules/cloud-aliyun/LINGYUN.Abp.Aliyun/README.md +++ b/aspnet-core/modules/cloud-aliyun/LINGYUN.Abp.Aliyun/README.md @@ -1,31 +1,3 @@ -# LINGYUN.Abp.Aliyun +# Oss-Management -阿里云sdk集成 - -参照:https://help.aliyun.com/document_detail/28763.html - -## 配置使用 - -模块按需引用 - -```csharp -[DependsOn(typeof(AbpAliyunModule))] -public class YouProjectModule : AbpModule -{ - // other -} -``` -## 配置项说明 - -* AliyunSettingNames.Authorization.RegionId 可选,区域,默认 default -* AliyunSettingNames.Authorization.AccessKeyId 必须,阿里云RAM账号的AccessKey ID -* AliyunSettingNames.Authorization.AccessKeySecret 必须,RAM账号的AccessKey Secret -* AliyunSettingNames.Authorization.UseSecurityTokenService 可选,建议,使用STS Token访问,按照阿里云文档,建议使用Sts Token访问API,默认false -* AliyunSettingNames.Authorization.RamRoleArn 可选,启用Sts Token之后必须配置,阿里云RAM角色ARN -* AliyunSettingNames.Authorization.RoleSessionName 可选,启用Sts Token之后的用户自定义令牌名称,用于访问审计 -* AliyunSettingNames.Authorization.DurationSeconds 可选,用户令牌的过期时间,单位为秒,默认3000 -* AliyunSettingNames.Authorization.Policy 可选,权限策略,为json字符串 - -## 其他 - -网络因素在高并发下可能会出现预期外的异常,考虑使用二级缓存 +File-Management更名为Oss-Management diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/CreateOssObjectInput.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/CreateOssObjectInput.cs index eee24f5b7..f96bd033a 100644 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/CreateOssObjectInput.cs +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/CreateOssObjectInput.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using Volo.Abp.Auditing; +using Volo.Abp.Validation; namespace LINGYUN.Abp.FileManagement { @@ -8,12 +10,16 @@ namespace LINGYUN.Abp.FileManagement public string Bucket { get; set; } public string Path { get; set; } public string Object { get; set; } + + [DisableAuditing] + [DisableValidation] public Stream Content { get; set; } public TimeSpan? ExpirationTime { get; set; } public void SetContent(Stream content) { Content = content; + Content?.Seek(0, SeekOrigin.Begin); } } } diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileCopyOrMoveDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileCopyOrMoveDto.cs deleted file mode 100644 index d399c5571..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileCopyOrMoveDto.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace LINGYUN.Abp.FileManagement -{ - public class FileCopyOrMoveDto - { - [StringLength(255)] - public string Path { get; set; } - - [Required] - [StringLength(255)] - public string Name { get; set; } - - [Required] - [StringLength(255)] - public string ToPath { get; set; } - - [StringLength(255)] - public string ToName { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileCreateDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileCreateDto.cs deleted file mode 100644 index 59da9f99f..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileCreateDto.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.IO; -using Volo.Abp.Auditing; -using Volo.Abp.Validation; - -namespace LINGYUN.Abp.FileManagement -{ - public class FileCreateDto - { - /// - /// 文件名 - /// - [Required] - [StringLength(255)] - public string FileName { get; set; } - /// - /// 文件路径 - /// - [StringLength(255)] - public string Path { get; set; } - /// - /// 文件数据,前端无需传递此参数,由控制器传递 - /// - [DisableAuditing] - [DisableValidation]// TODO: 需要禁用参数检查,否则会有一个框架方面的性能问题存在 - public byte[] Data { get; set; } - /// - /// 是否覆盖文件 - /// - public bool Rewrite { get; set; } = false; - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileDeleteDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileDeleteDto.cs deleted file mode 100644 index a12f6ff3c..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileDeleteDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace LINGYUN.Abp.FileManagement -{ - public class FileDeleteDto - { - [StringLength(255)] - public string Path { get; set; } - - [Required] - [StringLength(255)] - public string Name { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemDownloadDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemDownloadDto.cs deleted file mode 100644 index b421dda4a..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemDownloadDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Text; - -namespace LINGYUN.Abp.FileManagement -{ - public class FileSystemDownloadDto : FileSystemGetDto - { - /// - /// 当前字节数 - /// - public int CurrentByte { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemDto.cs deleted file mode 100644 index aecbd0be0..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace LINGYUN.Abp.FileManagement -{ - public class FileSystemDto - { - public FileSystemType Type { get; set; } - public string Name { get; set; } - public string Parent { get; set; } - public string Extension { get; set; } - public long? Size { get; set; } - public DateTime CreationTime { get; set; } - public DateTime? LastModificationTime { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemGetDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemGetDto.cs deleted file mode 100644 index 8c9619ba6..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemGetDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace LINGYUN.Abp.FileManagement -{ - public class FileSystemGetDto - { - [StringLength(255)] - public string Path { get; set; } - - [Required] - [StringLength(255)] - public string Name { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemType.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemType.cs deleted file mode 100644 index ecbcd214d..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace LINGYUN.Abp.FileManagement -{ - public enum FileSystemType - { - Folder = 0, - File = 1 - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemUpdateDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemUpdateDto.cs deleted file mode 100644 index 3f4193bf4..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FileSystemUpdateDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace LINGYUN.Abp.FileManagement -{ - public class FileSystemUpdateDto - { - [Required] - [StringLength(255)] - public string NewName { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderCopyDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderCopyDto.cs deleted file mode 100644 index ada1ca9a5..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderCopyDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace LINGYUN.Abp.FileManagement -{ - public class FolderCopyDto - { - [Required] - [StringLength(255)] - public string CopyToPath { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderCreateDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderCreateDto.cs deleted file mode 100644 index 9d2c09d93..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderCreateDto.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace LINGYUN.Abp.FileManagement -{ - public class FolderCreateDto - { - [Required] - [StringLength(255)] - public string Path { get; set; } - - public string Parent { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderMoveDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderMoveDto.cs deleted file mode 100644 index 760b79ad8..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/FolderMoveDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace LINGYUN.Abp.FileManagement -{ - public class FolderMoveDto - { - [Required] - [StringLength(255)] - public string MoveToPath { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetFileSystemListDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetFileSystemListDto.cs deleted file mode 100644 index 29b4f02cb..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetFileSystemListDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using Volo.Abp.Application.Dtos; - -namespace LINGYUN.Abp.FileManagement -{ - public class GetFileSystemListDto : PagedAndSortedResultRequestDto - { - // TODO: Windows最大路径长度,超过了貌似也无效了吧 - [StringLength(255)] - public string Parent { get; set; } - - public string Filter { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IFileSystemAppService.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IFileSystemAppService.cs deleted file mode 100644 index 4a5955161..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IFileSystemAppService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.IO; -using System.Threading.Tasks; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Application.Services; - -namespace LINGYUN.Abp.FileManagement -{ - public interface IFileSystemAppService : IApplicationService - { - Task GetAsync(FileSystemGetDto input); - - Task> GetListAsync(GetFileSystemListDto input); - - Task CreateFolderAsync(FolderCreateDto input); - - Task UpdateAsync([Required, StringLength(255)] string name, FileSystemUpdateDto input); - - Task DeleteFolderAsync([Required, StringLength(255)] string path); - - Task MoveFolderAsync([Required, StringLength(255)] string path, FolderMoveDto input); - - Task CopyFolderAsync([Required, StringLength(255)] string path, FolderCopyDto input); - - Task CreateFileAsync(FileCreateDto input); - - Task DeleteFileAsync(FileDeleteDto input); - - Task MoveFileAsync(FileCopyOrMoveDto input); - - Task CopyFileAsync(FileCopyOrMoveDto input); - - Task DownloadFileAsync(FileSystemGetDto input); - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/FileSystemAppService.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/FileSystemAppService.cs deleted file mode 100644 index a6ee61d96..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/FileSystemAppService.cs +++ /dev/null @@ -1,467 +0,0 @@ -using LINGYUN.Abp.FileManagement.Permissions; -using Microsoft.AspNetCore.Authorization; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Application.Dtos; -using Volo.Abp.BlobStoring; -using Volo.Abp.BlobStoring.FileSystem; - -namespace LINGYUN.Abp.FileManagement -{ - [Authorize(AbpFileManagementPermissions.FileSystem.Default)] - public class FileSystemAppService : FileManagementApplicationServiceBase, IFileSystemAppService - { - protected IBlobContainer BlobContainer { get; } - protected IBlobContainerConfigurationProvider BlobContainerConfigurationProvider { get; } - public FileSystemAppService( - IBlobContainer blobContainer, - IBlobContainerConfigurationProvider blobContainerConfigurationProvider) - { - BlobContainer = blobContainer; - BlobContainerConfigurationProvider = blobContainerConfigurationProvider; - } - - [Authorize(AbpFileManagementPermissions.FileSystem.FileManager.Copy)] - public virtual Task CopyFileAsync(FileCopyOrMoveDto input) - { - string fileSystemPath = GetFileSystemPath(input.Path); - var fileFullName = Path.Combine(fileSystemPath, input.Name); - if (!File.Exists(fileFullName)) - { - throw new UserFriendlyException(L["FilePathNotFound"]); - } - var copyToFilePath = GetFileSystemPath(input.ToPath); - var copyToFileFullName = Path.Combine(copyToFilePath, input.ToName ?? input.Name); - if (File.Exists(copyToFileFullName)) - { - throw new UserFriendlyException(L["FilePathAlreadyExists"]); - } - - File.Copy(fileFullName, copyToFileFullName); - - return Task.CompletedTask; - } - - [Authorize(AbpFileManagementPermissions.FileSystem.Copy)] - public virtual Task CopyFolderAsync([Required, StringLength(255)] string path, FolderCopyDto input) - { - string fileSystemPath = GetFileSystemPath(path); - if (!Directory.Exists(fileSystemPath)) - { - throw new UserFriendlyException(L["PathNotFound"]); - } - var copyToFilePath = GetFileSystemPath(input.CopyToPath); - if (Directory.Exists(copyToFilePath)) - { - throw new UserFriendlyException(L["FilePathAlreadyExists"]); - } - - CopyDirectory(fileSystemPath, copyToFilePath); - - return Task.CompletedTask; - } - - [Authorize(AbpFileManagementPermissions.FileSystem.FileManager.Create)] - public virtual async Task CreateFileAsync(FileCreateDto input) - { - string fileSystemPath = GetFileSystemPath(input.Path); - fileSystemPath = Path.Combine(fileSystemPath, input.FileName); - var blobName = GetFileSystemRelativePath(fileSystemPath); - // 去除第一个路径标识符 - blobName = blobName.RemovePreFix("/", "\\"); - if (!input.Rewrite && await BlobContainer.ExistsAsync(blobName)) - { - throw new UserFriendlyException(L["FilePathAlreadyExists"]); - } - await BlobContainer.SaveAsync(blobName, input.Data, input.Rewrite); - Array.Clear(input.Data, 0, input.Data.Length); - } - - [Authorize(AbpFileManagementPermissions.FileSystem.Create)] - public virtual Task CreateFolderAsync(FolderCreateDto input) - { - string fileSystemPath = GetFileSystemBashPath(); - if (!input.Parent.IsNullOrWhiteSpace()) - { - fileSystemPath = GetFileSystemPath(input.Parent); - } - var newFloderPath = Path.Combine(fileSystemPath, input.Path); - if (Directory.Exists(newFloderPath)) - { - throw new UserFriendlyException(L["PathAlreadyExists"]); - } - Directory.CreateDirectory(newFloderPath); - - return Task.CompletedTask; - } - - [Authorize(AbpFileManagementPermissions.FileSystem.FileManager.Delete)] - public virtual Task DeleteFileAsync(FileDeleteDto input) - { - var fileSystemPath = GetFileSystemPath(input.Path); - fileSystemPath = Path.Combine(fileSystemPath, input.Name); - if (File.Exists(fileSystemPath)) - { - File.Delete(fileSystemPath); - } - return Task.CompletedTask; - } - - [Authorize(AbpFileManagementPermissions.FileSystem.Delete)] - public virtual Task DeleteFolderAsync([Required, StringLength(255)] string path) - { - string fileSystemPath = GetFileSystemPath(path); - if (!Directory.Exists(fileSystemPath)) - { - throw new UserFriendlyException(L["FilePathNotFound"]); - } - var fileSystemChildrenPath = Directory.GetDirectories(fileSystemPath); - if (fileSystemChildrenPath.Length > 0) - { - throw new UserFriendlyException(L["PathCannotBeDeletedWithNotEmpty"]); - } - var fileSystemPathFiles = Directory.GetFiles(fileSystemPath); - if (fileSystemPathFiles.Length > 0) - { - throw new UserFriendlyException(L["PathCannotBeDeletedWithNotEmpty"]); - } - Directory.Delete(fileSystemPath); - return Task.CompletedTask; - } - - [Authorize(AbpFileManagementPermissions.FileSystem.FileManager.Download)] - public virtual async Task DownloadFileAsync(FileSystemGetDto input) - { - var fileSystemPath = GetFileSystemPath(input.Path); - fileSystemPath = Path.Combine(fileSystemPath, input.Name); - var blobName = GetFileSystemRelativePath(fileSystemPath); - // 去除第一个路径标识符 - blobName = blobName.RemovePreFix("/", "\\"); - return await BlobContainer.GetAsync(blobName); - } - - public virtual Task GetAsync(FileSystemGetDto input) - { - var fileSystemPath = GetFileSystemPath(input.Path); - fileSystemPath = Path.Combine(fileSystemPath, input.Name); - if (File.Exists(fileSystemPath)) - { - var fileInfo = new FileInfo(fileSystemPath); - var fileSystem = new FileSystemDto - { - Type = FileSystemType.File, - Name = fileInfo.Name, - Size = fileInfo.Length, - Extension = fileInfo.Extension, - CreationTime = fileInfo.CreationTime, - LastModificationTime = fileInfo.LastWriteTime - }; - if (fileInfo.Directory != null && !fileInfo.Directory.FullName.IsNullOrWhiteSpace()) - { - fileSystem.Parent = GetFileSystemRelativePath(fileInfo.Directory.FullName); - } - return Task.FromResult(fileSystem); - } - if (Directory.Exists(fileSystemPath)) - { - var directoryInfo = new DirectoryInfo(fileSystemPath); - var fileSystem = new FileSystemDto - { - Type = FileSystemType.Folder, - Name = directoryInfo.Name, - CreationTime = directoryInfo.CreationTime, - LastModificationTime = directoryInfo.LastWriteTime - }; - if (directoryInfo.Parent != null && !directoryInfo.Parent.FullName.IsNullOrWhiteSpace()) - { - fileSystem.Parent = GetFileSystemRelativePath(directoryInfo.Parent.FullName); - } - return Task.FromResult(fileSystem); - } - throw new UserFriendlyException(L["FilePathNotFound"]); - } - - public virtual Task> GetListAsync(GetFileSystemListDto input) - { - List fileSystems = new List(); - - string fileSystemPath = GetFileSystemBashPath(); - if (!input.Parent.IsNullOrWhiteSpace()) - { - fileSystemPath = GetFileSystemPath(input.Parent); - } - var directoryInfo = new DirectoryInfo(fileSystemPath); - if (!directoryInfo.Exists) - { - return Task.FromResult(new PagedResultDto(0, fileSystems)); - } - // 查询全部文件系统 - var fileSystemInfos = directoryInfo.GetFileSystemInfos(); - // 指定搜索条件查询目录 - FileSystemInfo[] fileSystemInfoSearchChildren; - if (!input.Filter.IsNullOrWhiteSpace()) - { - var searchPattern = $"*{input.Filter}*"; - fileSystemInfoSearchChildren = directoryInfo.GetFileSystemInfos(searchPattern); - } - else - { - fileSystemInfoSearchChildren = directoryInfo.GetFileSystemInfos(); - } - - fileSystemInfoSearchChildren = fileSystemInfoSearchChildren - .Skip((input.SkipCount - 1) * input.MaxResultCount) - .Take(input.MaxResultCount) - .ToArray(); - - foreach (var fileSystemInfo in fileSystemInfoSearchChildren) - { - var fileSystem = new FileSystemDto - { - Name = fileSystemInfo.Name, - CreationTime = fileSystemInfo.CreationTime, - LastModificationTime = fileSystemInfo.LastWriteTime, - }; - - if (fileSystemInfo is FileInfo fileInfo) - { - fileSystem.Type = FileSystemType.File; - fileSystem.Size = fileInfo.Length; - fileSystem.Extension = fileInfo.Extension; - if (fileInfo.Directory != null && !fileInfo.Directory.FullName.IsNullOrWhiteSpace()) - { - fileSystem.Parent = GetFileSystemRelativePath(fileInfo.Directory.FullName); - } - } - else if (fileSystemInfo is DirectoryInfo directory) - { - fileSystem.Type = FileSystemType.Folder; - if (directory.Parent != null && !directory.Parent.FullName.IsNullOrWhiteSpace()) - { - fileSystem.Parent = GetFileSystemRelativePath(directory.Parent.FullName); - } - } - fileSystems.Add(fileSystem); - } - - fileSystems = fileSystems - .OrderBy(f => f.Type) - .ThenBy(f => f.Name) - .ToList(); - - return Task.FromResult(new PagedResultDto( - fileSystemInfos.Length, fileSystems - )); - } - - [Authorize(AbpFileManagementPermissions.FileSystem.FileManager.Move)] - public virtual Task MoveFileAsync(FileCopyOrMoveDto input) - { - string fileSystemPath = GetFileSystemPath(input.Path); - fileSystemPath = Path.Combine(fileSystemPath, input.Name); - if (!File.Exists(fileSystemPath)) - { - throw new UserFriendlyException(L["FilePathNotFound"]); - } - var moveToFilePath = GetFileSystemPath(input.ToPath); - moveToFilePath = Path.Combine(moveToFilePath, input.ToName ?? input.Name); - if (File.Exists(moveToFilePath)) - { - throw new UserFriendlyException(L["FilePathAlreadyExists"]); - } - - File.Move(fileSystemPath, moveToFilePath); - - return Task.CompletedTask; - } - - [Authorize(AbpFileManagementPermissions.FileSystem.Move)] - public virtual Task MoveFolderAsync([Required, StringLength(255)] string path, FolderMoveDto input) - { - string fileSystemPath = GetFileSystemPath(path); - if (!Directory.Exists(fileSystemPath)) - { - throw new UserFriendlyException(L["FilePathNotFound"]); - } - var moveToFilePath = GetFileSystemPath(input.MoveToPath); - if (Directory.Exists(moveToFilePath)) - { - throw new UserFriendlyException(L["FilePathAlreadyExists"]); - } - - Directory.Move(fileSystemPath, moveToFilePath); - - return Task.CompletedTask; - } - - [Authorize(AbpFileManagementPermissions.FileSystem.Update)] - public virtual Task UpdateAsync([Required, StringLength(255)] string name, FileSystemUpdateDto input) - { - string fileSystemPath = GetFileSystemPath(name); - var renameFilePath = GetFileSystemPath(input.NewName); - if (File.Exists(fileSystemPath)) - { - if (File.Exists(renameFilePath)) - { - throw new UserFriendlyException(L["FilePathAlreadyExists"]); - } - File.Move(fileSystemPath, renameFilePath); - - var fileInfo = new FileInfo(renameFilePath); - var fileSystem = new FileSystemDto - { - Type = FileSystemType.File, - Name = fileInfo.Name, - Size = fileInfo.Length, - Extension = fileInfo.Extension, - CreationTime = fileInfo.CreationTime, - LastModificationTime = fileInfo.LastWriteTime - }; - if (fileInfo.Directory != null && !fileInfo.Directory.FullName.IsNullOrWhiteSpace()) - { - fileSystem.Parent = GetFileSystemRelativePath(fileInfo.Directory.FullName); - } - return Task.FromResult(fileSystem); - } - if (Directory.Exists(fileSystemPath)) - { - if (Directory.Exists(renameFilePath)) - { - throw new UserFriendlyException(L["FilePathAlreadyExists"]); - } - - Directory.Move(fileSystemPath, renameFilePath); - - var directoryInfo = new DirectoryInfo(renameFilePath); - var fileSystem = new FileSystemDto - { - Type = FileSystemType.Folder, - Name = directoryInfo.Name, - CreationTime = directoryInfo.CreationTime, - LastModificationTime = directoryInfo.LastWriteTime - }; - if (directoryInfo.Parent != null && !directoryInfo.Parent.FullName.IsNullOrWhiteSpace()) - { - fileSystem.Parent = GetFileSystemRelativePath(directoryInfo.Parent.FullName); - } - return Task.FromResult(fileSystem); - } - throw new UserFriendlyException(L["FilePathNotFound"]); - } - /// - /// 获取文件系统相对路径 - /// - /// - /// - protected virtual string GetFileSystemRelativePath(string path) - { - // 去除完整路径中的文件系统根目录 - var fileSystemConfiguration = GetFileSystemBlobProviderConfiguration(); - var blobPath = fileSystemConfiguration.BasePath; - // 去除租户或宿主目录 - if (CurrentTenant.Id == null) - { - blobPath = Path.Combine(blobPath, "host"); - } - else - { - blobPath = Path.Combine(blobPath, "tenants", CurrentTenant.Id.Value.ToString("D")); - } - // 去除完整路径中的容器根目录 - var containerName = BlobContainerNameAttribute.GetContainerName(); - if (path.Contains(containerName)) - { - blobPath = Path.Combine(blobPath, containerName); - } - path = path.Replace(blobPath, ""); - path = path.Replace('/', Path.DirectorySeparatorChar); - path = path.Replace('\\', Path.DirectorySeparatorChar); - return path; - } - /// - /// 获取合并的文件路径 - /// - /// - /// - protected virtual string GetFileSystemPath(string path) - { - var fileSystemConfiguration = GetFileSystemBlobProviderConfiguration(); - var blobPath = GetFileSystemBashPath(); - - if (!path.IsNullOrWhiteSpace() && fileSystemConfiguration.AppendContainerNameToBasePath) - { - path = path.Replace('/', Path.DirectorySeparatorChar); - path = path.Replace('\\', Path.DirectorySeparatorChar); - // 去除第一个路径标识符 - path = path.RemovePreFix("/", "\\"); - blobPath = Path.Combine(blobPath, path); - } - - return blobPath; - } - /// - /// 获取文件系统存储路径 - /// - /// - protected virtual string GetFileSystemBashPath() - { - var fileSystemConfiguration = GetFileSystemBlobProviderConfiguration(); - var blobPath = fileSystemConfiguration.BasePath; - blobPath = Path.Combine(Directory.GetCurrentDirectory(), blobPath); - if (CurrentTenant.Id == null) - { - blobPath = Path.Combine(blobPath, "host"); - } - else - { - blobPath = Path.Combine(blobPath, "tenants", CurrentTenant.Id.Value.ToString("D")); - } - var containerName = BlobContainerNameAttribute.GetContainerName(); - - blobPath = Path.Combine(blobPath, containerName); - - if (!Directory.Exists(blobPath)) - { - Directory.CreateDirectory(blobPath); - } - - return blobPath; - } - - protected virtual FileSystemBlobProviderConfiguration GetFileSystemBlobProviderConfiguration() - { - var blobConfiguration = BlobContainerConfigurationProvider - .Get(); - return blobConfiguration.GetFileSystemConfiguration(); - } - - protected void CopyDirectory(string sourcePath, string copyToPath) - { - var sourceDirectory = new DirectoryInfo(sourcePath); - var fileSystemInfos = sourceDirectory.GetFileSystemInfos(); - - foreach (var fileSystemInfo in fileSystemInfos) - { - var copyToFilePath = Path.Combine(copyToPath, fileSystemInfo.Name); - if (fileSystemInfo is DirectoryInfo) - { - if (!Directory.Exists(copyToFilePath)) - { - Directory.CreateDirectory(copyToFilePath); - } - CopyDirectory(fileSystemInfo.FullName, copyToFilePath); - } - else - { - File.Copy(fileSystemInfo.FullName, copyToFilePath, true); - } - } - - } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/FileManagementErrorCodes.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/FileManagementErrorCodes.cs index f746ac847..bb141b8cc 100644 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/FileManagementErrorCodes.cs +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/FileManagementErrorCodes.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace LINGYUN.Abp.FileManagement +namespace LINGYUN.Abp.FileManagement { public static class FileManagementErrorCodes { @@ -15,5 +11,7 @@ namespace LINGYUN.Abp.FileManagement public const string ObjectDeleteWithNotEmpty = Namespace + ":020001"; public const string ObjectAlreadyExists = Namespace + ":020402"; public const string ObjectNotFound = Namespace + ":020404"; + + public const string OssNameHasTooLong = Namespace + ":000405"; } } diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/en.json b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/en.json index 593dd067b..9226adb40 100644 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/en.json +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/en.json @@ -7,6 +7,7 @@ "Abp.FileManagement:020001": "An object that has more than one child cannot be deleted!", "Abp.FileManagement:020402": "The object name already exists!", "Abp.FileManagement:020404": "The queried object could not be found!", + "Abp.FileManagement:000405": "The path object name has exceeded the allowable maximum length and cannot continue to create a new object!", "Permission:FileManagement": "File management", "Permission:FileSystem": "File system", "Permission:FileManager": "Files", diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/zh-Hans.json index f33ccb294..a5ed73cd8 100644 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/zh-Hans.json @@ -7,6 +7,7 @@ "Abp.FileManagement:020001": "不能删除存在多个子级的对象!", "Abp.FileManagement:020402": "对象名称已经存在!", "Abp.FileManagement:020404": "未能找到查询的对象!", + "Abp.FileManagement:000405": "此路径对象名称已超出允许的最大长度,无法继续创建新对象!", "Permission:FileManagement": "文件管理", "Permission:FileSystem": "文件系统", "Permission:FileManager": "文件", diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN.Abp.FileManagement.Domain.csproj b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN.Abp.FileManagement.Domain.csproj index 2065cb5f0..b71d697a1 100644 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN.Abp.FileManagement.Domain.csproj +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN.Abp.FileManagement.Domain.csproj @@ -8,7 +8,7 @@ - + diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssContainer.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssContainer.cs index 58c0e2f79..8db2b4542 100644 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssContainer.cs +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssContainer.cs @@ -1,16 +1,16 @@ -using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Volo.Abp; using Volo.Abp.BlobStoring; using Volo.Abp.BlobStoring.FileSystem; -using Volo.Abp.MultiTenancy; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.DependencyInjection; using Volo.Abp.IO; -using Volo.Abp; +using Volo.Abp.MultiTenancy; namespace LINGYUN.Abp.FileManagement.FileSystem { @@ -44,11 +44,23 @@ namespace LINGYUN.Abp.FileManagement.FileSystem public virtual Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request) { - var filesPath = request.Objects.Select(x => CalculateFilePath(request.Bucket, x)); + var objectPath = !request.Path.IsNullOrWhiteSpace() + ? request.Path.EnsureEndsWith('/') + : ""; + var filesPath = request.Objects.Select(x => CalculateFilePath(request.Bucket, objectPath + x)); foreach (var file in filesPath) { - if (File.Exists(file)) + if (Directory.Exists(file)) + { + if (Directory.GetFileSystemEntries(file).Length > 0) + { + throw new BusinessException(code: FileManagementErrorCodes.ContainerDeleteWithNotEmpty); + // throw new ContainerDeleteWithNotEmptyException("00101", $"Can't not delete container {name}, because it is not empty!"); + } + Directory.Delete(file); + } + else if (File.Exists(file)) { File.Delete(file); } @@ -60,6 +72,7 @@ namespace LINGYUN.Abp.FileManagement.FileSystem public virtual Task CreateAsync(string name) { var filePath = CalculateFilePath(name); + ThrowOfPathHasTooLong(filePath); if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); @@ -91,6 +104,8 @@ namespace LINGYUN.Abp.FileManagement.FileSystem var filePath = CalculateFilePath(request.Bucket, objectName); if (!request.Content.IsNullOrEmpty()) { + ThrowOfPathHasTooLong(filePath); + if (File.Exists(filePath)) { throw new BusinessException(code: FileManagementErrorCodes.ObjectAlreadyExists); @@ -126,6 +141,7 @@ namespace LINGYUN.Abp.FileManagement.FileSystem } else { + ThrowOfPathHasTooLong(filePath); if (Directory.Exists(filePath)) { throw new BusinessException(code: FileManagementErrorCodes.ObjectAlreadyExists); @@ -159,14 +175,15 @@ namespace LINGYUN.Abp.FileManagement.FileSystem var filePath = CalculateFilePath(name); if (!Directory.Exists(filePath)) { - // 非空目录无法删除 - if (Directory.GetFiles(filePath).Length > 0) - { - throw new BusinessException(code: FileManagementErrorCodes.ContainerDeleteWithNotEmpty); - // throw new ContainerDeleteWithNotEmptyException("00101", $"Can't not delete container {name}, because it is not empty!"); - } - Directory.Delete(filePath); + throw new BusinessException(code: FileManagementErrorCodes.ContainerNotFound); } + // 非空目录无法删除 + if (Directory.GetFileSystemEntries(filePath).Length > 0) + { + throw new BusinessException(code: FileManagementErrorCodes.ContainerDeleteWithNotEmpty); + // throw new ContainerDeleteWithNotEmptyException("00101", $"Can't not delete container {name}, because it is not empty!"); + } + Directory.Delete(filePath); return Task.CompletedTask; } @@ -177,13 +194,13 @@ namespace LINGYUN.Abp.FileManagement.FileSystem ? request.Object : request.Path.EnsureEndsWith('/') + request.Object; var filePath = CalculateFilePath(request.Bucket, objectName); - if (!File.Exists(filePath)) + if (File.Exists(filePath)) { File.Delete(filePath); } else if (Directory.Exists(filePath)) { - if (Directory.GetFiles(filePath).Length > 0) + if (Directory.GetFileSystemEntries(filePath).Length > 0) { throw new BusinessException(code: FileManagementErrorCodes.ObjectDeleteWithNotEmpty); } @@ -508,5 +525,15 @@ namespace LINGYUN.Abp.FileManagement.FileSystem return blobPath; } + + private void ThrowOfPathHasTooLong(string path) + { + // Windows 133 260 + // Linux 255 4096 + //if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && path.Length >= 255) // 预留5位 + //{ + // throw new BusinessException(code: FileManagementErrorCodes.OssNameHasTooLong); + //} + } } } diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileSystemController.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileSystemController.cs deleted file mode 100644 index 136530588..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileSystemController.cs +++ /dev/null @@ -1,265 +0,0 @@ -using LINGYUN.Abp.FileManagement.Localization; -using LINGYUN.Abp.FileManagement.Permissions; -using LINGYUN.Abp.FileManagement.Settings; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.StaticFiles; -using System; -using System.ComponentModel.DataAnnotations; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Application.Dtos; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.IO; -using Volo.Abp.Settings; -using Volo.Abp.Features; -using LINGYUN.Abp.FileManagement.Features; - -namespace LINGYUN.Abp.FileManagement -{ - [Controller] - [RemoteService(Name = "AbpFileManagement")] - [Area("file-management")] - [Route("api/file-management/file-system")] - public class FileSystemController : AbpController - { - protected ISettingProvider SettingProvider { get; } - protected IFileSystemAppService FileSystemAppService { get; } - - public FileSystemController( - ISettingProvider settingProvider, - IFileSystemAppService fileSystemAppService) - { - SettingProvider = settingProvider; - FileSystemAppService = fileSystemAppService; - LocalizationResource = typeof(AbpFileManagementResource); - } - - [HttpPut] - [Route("files/copy")] - public virtual async Task CopyFileAsync(FileCopyOrMoveDto input) - { - await FileSystemAppService.CopyFileAsync(input); - } - - [HttpPut] - [Route("folders/copy")] - public virtual async Task CopyFolderAsync([Required, StringLength(255)] string path, FolderCopyDto input) - { - await FileSystemAppService.CopyFolderAsync(path, input); - } - - [HttpPost] - [Route("files")] - [RequiresFeature(AbpFileManagementFeatureNames.FileSystem.UploadFile)] - [Authorize(AbpFileManagementPermissions.FileSystem.FileManager.Create)] - public virtual async Task CreateFileAsync([FromForm] FileUploadDto input) - { - // 检查文件大小 - var fileSizeLimited = await SettingProvider - .GetAsync( - AbpFileManagementSettingNames.FileLimitLength, - AbpFileManagementSettingNames.DefaultFileLimitLength); - if (fileSizeLimited * 1024 * 1024 < input.TotalSize) - { - throw new UserFriendlyException(L["UploadFileSizeBeyondLimit", fileSizeLimited]); - } - // 采用分块模式上传文件 - - // 保存分块到临时目录 - var fileName = input.FileName; - // 文件扩展名 - var fileExtensionName = FileHelper.GetExtension(fileName); - var fileAllowExtension = await SettingProvider - .GetOrDefaultAsync(AbpFileManagementSettingNames.AllowFileExtensions, ServiceProvider); - // 检查文件扩展名 - if (!fileAllowExtension.Split(',') - .Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) - { - throw new UserFriendlyException(L["NotAllowedFileExtensionName", fileExtensionName]); - } - // 以上传的文件名创建一个临时目录 - var tempFilePath = Path.Combine( - Path.GetTempPath(), - "lingyun-abp-file-management", - "upload", - string.Concat(input.Path ?? "", input.FileName).ToMd5()); - DirectoryHelper.CreateIfNotExists(tempFilePath); - // 以上传的分片索引创建临时文件 - var tempSavedFile = Path.Combine(tempFilePath, $"{input.ChunkNumber}.{fileExtensionName}"); - try - { - if (HttpContext.RequestAborted.IsCancellationRequested) - { - // 如果取消请求,删除临时目录 - Directory.Delete(tempFilePath, true); - return; - } - - if (input.File != null) - { - // 保存临时文件 - using (var fs = new FileStream(tempSavedFile, FileMode.Create, FileAccess.Write)) - { - // 写入当前分片文件 - await input.File.CopyToAsync(fs); - } - } - - if (input.ChunkNumber == input.TotalChunks) - { - // 合并文件 - var mergeSavedFile = Path.Combine(tempFilePath, $"{fileName}"); - // 获取并排序所有分片文件 - var mergeFiles = Directory.GetFiles(tempFilePath).OrderBy(f => f.Length).ThenBy(f => f); - // 创建临时合并文件 - input.Data = new byte[0]; - foreach (var mergeFile in mergeFiles) - { - // 读取当前文件字节 - var mergeFileBytes = await FileHelper.ReadAllBytesAsync(mergeFile); - // 写入到合并文件流 - input.Data = input.Data.Concat(mergeFileBytes).ToArray(); - Array.Clear(mergeFileBytes,0, mergeFileBytes.Length); - // 删除已参与合并的临时文件分片 - FileHelper.DeleteIfExists(mergeFile); - } - await FileSystemAppService.CreateFileAsync(input); - // 文件保存之后删除临时文件目录 - Directory.Delete(tempFilePath, true); - } - } - catch - { - // 发生异常删除临时文件目录 - Directory.Delete(tempFilePath, true); - throw; - } - } - - [HttpPost] - [Route("folders")] - public virtual async Task CreateFolderAsync(FolderCreateDto input) - { - await FileSystemAppService.CreateFolderAsync(input); - } - - [HttpDelete] - [Route("files")] - public virtual async Task DeleteFileAsync(FileDeleteDto input) - { - await FileSystemAppService.DeleteFileAsync(input); - } - - [HttpDelete] - [Route("folders")] - public virtual async Task DeleteFolderAsync([Required, StringLength(255)] string path) - { - await FileSystemAppService.DeleteFolderAsync(path); - } - - [HttpGet] - [Route("files")] - [RequiresFeature(AbpFileManagementFeatureNames.FileSystem.DownloadFile)] - [Authorize(AbpFileManagementPermissions.FileSystem.FileManager.Download)] - public virtual async Task DownloadFileAsync(FileSystemDownloadDto input) - { - var tempFileName = string.Concat(input.Path ?? "", input.Name); - tempFileName = tempFileName.ToMd5() + Path.GetExtension(input.Name); - // 以上传的文件名创建一个临时目录 - var tempFilePath = Path.Combine( - Path.GetTempPath(), - "lingyun-abp-file-management", - "download"); - DirectoryHelper.CreateIfNotExists(tempFilePath); - tempFilePath = Path.Combine(tempFilePath, tempFileName); - long contentLength = 0L; - // 单个分块大小 2MB - int bufferSize = 2 * 1024 * 1024; - using (new DisposeAction(() => - { - // 最终下载完毕后,删除临时文件 - if (bufferSize + input.CurrentByte > contentLength) - { - FileHelper.DeleteIfExists(tempFilePath); - } - })) - { - if (!System.IO.File.Exists(tempFilePath)) - { - var blobStream = await FileSystemAppService.DownloadFileAsync(input); - using (var tempFileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write)) - { - blobStream.Position = 0; - await blobStream.CopyToAsync(tempFileStream); - } - } - // 读取缓存文件 - using var fileStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.Read); - // 得到文件扩展名 - var fileExt = Path.GetExtension(input.Name); - var provider = new FileExtensionContentTypeProvider(); - // Http响应标头的文件类型 - string memi = provider.Mappings[fileExt]; - // 文件大小 - contentLength = fileStream.Length; - if (bufferSize > contentLength) - { - var currentTransferBytes = await fileStream.GetAllBytesAsync(); - // 写入响应流 - return File(currentTransferBytes, memi, input.Name); - } - else - { - // 当前分页传输字节 - byte[] currentTransferBytes = new byte[bufferSize]; - if (input.CurrentByte + bufferSize >= contentLength) - { - currentTransferBytes = new byte[contentLength - input.CurrentByte]; - } - // 读取文件流中的当前分块区段 - fileStream.Seek(input.CurrentByte, SeekOrigin.Begin); - await fileStream.ReadAsync(currentTransferBytes, 0, currentTransferBytes.Length); - // 写入响应流 - return File(currentTransferBytes, memi, input.Name); - } - } - } - - [HttpGet] - [Route("profile")] - public virtual async Task GetAsync(FileSystemGetDto input) - { - return await FileSystemAppService.GetAsync(input); - } - - [HttpGet] - public virtual async Task> GetListAsync(GetFileSystemListDto input) - { - return await FileSystemAppService.GetListAsync(input); - } - - [HttpPut] - [Route("files/move")] - public virtual async Task MoveFileAsync(FileCopyOrMoveDto input) - { - await FileSystemAppService.MoveFileAsync(input); - } - - [HttpPut] - [Route("folders/move")] - public virtual async Task MoveFolderAsync([Required, StringLength(255)] string path, FolderMoveDto input) - { - await FileSystemAppService.MoveFolderAsync(path, input); - } - - [HttpPut] - public virtual async Task UpdateAsync([Required, StringLength(255)] string name, FileSystemUpdateDto input) - { - return await FileSystemAppService.UpdateAsync(name, input); - } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileUploadDto.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileUploadDto.cs deleted file mode 100644 index 490f4847e..000000000 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileUploadDto.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.AspNetCore.Http; -using System.ComponentModel.DataAnnotations; - -namespace LINGYUN.Abp.FileManagement -{ - public class FileUploadDto : FileCreateDto - { - /// - /// 常规块大小 - /// - [Required] - public int ChunkSize { get; set; } - /// - /// 当前块大小 - /// - [Required] - public int CurrentChunkSize { get; set; } - /// - /// 当前上传中块的索引 - /// - [Required] - public int ChunkNumber { get; set; } - /// - /// 块总数 - /// - [Required] - public int TotalChunks { get; set; } - /// - /// 总文件大小 - /// - [Required] - public int TotalSize { get; set; } - public IFormFile File { get; set; } - } -} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileValidater.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileValidater.cs new file mode 100644 index 000000000..4640a989a --- /dev/null +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/FileValidater.cs @@ -0,0 +1,96 @@ +using LINGYUN.Abp.FileManagement.Settings; +using Microsoft.Extensions.Caching.Memory; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.DependencyInjection; +using Volo.Abp.IO; +using Volo.Abp.Settings; +using Microsoft.Extensions.Localization; +using LINGYUN.Abp.FileManagement.Localization; + +namespace LINGYUN.Abp.FileManagement +{ + public class FileValidater : IFileValidater, ISingletonDependency + { + private readonly IMemoryCache _cache; + private readonly ISettingProvider _settingProvider; + private readonly IServiceProvider _serviceProvider; + private readonly IStringLocalizer _stringLocalizer; + + public FileValidater( + IMemoryCache cache, + ISettingProvider settingProvider, + IServiceProvider serviceProvider, + IStringLocalizer stringLocalizer) + { + _cache = cache; + _settingProvider = settingProvider; + _serviceProvider = serviceProvider; + _stringLocalizer = stringLocalizer; + } + + public virtual async Task ValidationAsync(UploadOssObjectInput input) + { + var validation = await GetByCacheItemAsync(); + if (validation.SizeLimit * 1024 * 1024 < input.TotalSize) + { + throw new UserFriendlyException(_stringLocalizer["UploadFileSizeBeyondLimit", validation.SizeLimit]); + } + var fileExtensionName = FileHelper.GetExtension(input.FileName); + if (!validation.AllowedExtensions + .Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) + { + throw new UserFriendlyException(_stringLocalizer["NotAllowedFileExtensionName", fileExtensionName]); + } + } + + protected virtual async Task GetByCacheItemAsync() + { + var fileValidation = _cache.Get(FileValidation.CacheKey); + if (fileValidation == null) + { + fileValidation = await GetBySettingAsync(); + _cache.Set(FileValidation.CacheKey, + fileValidation, + new MemoryCacheEntryOptions + { + AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(2) + }); + } + return fileValidation; + } + + protected virtual async Task GetBySettingAsync() + { + var fileSizeLimited = await _settingProvider + .GetAsync( + AbpFileManagementSettingNames.FileLimitLength, + AbpFileManagementSettingNames.DefaultFileLimitLength); + var fileAllowExtension = await _settingProvider + .GetOrDefaultAsync(AbpFileManagementSettingNames.AllowFileExtensions, _serviceProvider); + + return new FileValidation(fileSizeLimited, fileAllowExtension.Split(',')); + } + } + + public class FileValidation + { + public const string CacheKey = "Abp.FileManagement.FileValidation"; + public int SizeLimit { get; set; } + public string[] AllowedExtensions { get; set; } + public FileValidation() + { + + } + + public FileValidation( + int sizeLimit, + string[] allowedExtensions) + { + SizeLimit = sizeLimit; + AllowedExtensions = allowedExtensions; + } + } +} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/IFileValidater.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/IFileValidater.cs new file mode 100644 index 000000000..c6bb68030 --- /dev/null +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/IFileValidater.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.FileManagement +{ + public interface IFileValidater + { + Task ValidationAsync(UploadOssObjectInput input); + } +} diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/OssObjectController.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/OssObjectController.cs index f803316d5..dcf865542 100644 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/OssObjectController.cs +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/OssObjectController.cs @@ -1,9 +1,16 @@ -using Microsoft.AspNetCore.Mvc; +using LINGYUN.Abp.FileManagement.Settings; +using Microsoft.AspNetCore.Mvc; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Linq; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Auditing; +using Volo.Abp.IO; +using Volo.Abp.Settings; using Volo.Abp.Validation; namespace LINGYUN.Abp.FileManagement @@ -13,11 +20,14 @@ namespace LINGYUN.Abp.FileManagement [Route("api/file-management/objects")] public class OssObjectController : AbpController, IOssObjectAppService { + protected IFileValidater FileValidater { get; } protected IOssObjectAppService OssObjectAppService { get; } public OssObjectController( + IFileValidater fileValidater, IOssObjectAppService ossObjectAppService) { + FileValidater = fileValidater; OssObjectAppService = ossObjectAppService; } @@ -29,30 +39,82 @@ namespace LINGYUN.Abp.FileManagement [HttpPost] [Route("upload")] - public virtual async Task UploadAsync([FromForm] UploadOssObjectInput input) + [DisableAuditing] + public virtual async Task UploadAsync([FromForm] UploadOssObjectInput input) { - var createOssObjectInput = new CreateOssObjectInput + await FileValidater.ValidationAsync(input); + // 以上传的文件名创建一个临时目录 + var tempFilePath = Path.Combine( + Path.GetTempPath(), + "lingyun-abp-application", + "upload-tmp", + string.Concat(input.Path ?? "", input.FileName).ToMd5()); + DirectoryHelper.CreateIfNotExists(tempFilePath); + // 以上传的分片索引创建临时文件 + var tempSavedFile = Path.Combine(tempFilePath, $"{input.ChunkNumber}.uploadtmp"); + try { - Bucket = input.Bucket, - Path = input.Path, - Object = input.Name - }; - if (input.File != null) + if (HttpContext.RequestAborted.IsCancellationRequested) + { + // 如果取消请求,删除临时目录 + Directory.Delete(tempFilePath, true); + return; + } + + if (input.File != null) + { + // 保存临时文件 + using (var fs = new FileStream(tempSavedFile, FileMode.Create, FileAccess.Write)) + { + // 写入当前分片文件 + await input.File.CopyToAsync(fs); + } + } + + if (input.ChunkNumber == input.TotalChunks) + { + var createOssObjectInput = new CreateOssObjectInput + { + Bucket = input.Bucket, + Path = input.Path, + Object = input.FileName + }; + // 合并文件 + var mergeSavedFile = Path.Combine(tempFilePath, $"{input.FileName}"); + // 获取并排序所有分片文件 + var mergeFiles = Directory.GetFiles(tempFilePath).OrderBy(f => f.Length).ThenBy(f => f); + // 创建临时合并文件 + using (var memoryStream = new MemoryStream()) + { + foreach (var mergeFile in mergeFiles) + { + // 读取当前文件字节 + var mergeFileBytes = await FileHelper.ReadAllBytesAsync(mergeFile); + // 写入到合并文件流 + await memoryStream.WriteAsync(mergeFileBytes, HttpContext.RequestAborted); + Array.Clear(mergeFileBytes, 0, mergeFileBytes.Length); + // 删除已参与合并的临时文件分片 + FileHelper.DeleteIfExists(mergeFile); + } + createOssObjectInput.SetContent(memoryStream); + + await OssObjectAppService.CreateAsync(createOssObjectInput); + // 文件保存之后删除临时文件目录 + Directory.Delete(tempFilePath, true); + } + } + } + catch { - //if (input.File.Length <= 0) - //{ - // ThrowValidationException(L["FileNotBeNullOrEmpty"], "File"); - //} - createOssObjectInput.Object = input.File.FileName; - createOssObjectInput.Content = input.File.OpenReadStream(); + // 发生异常删除临时文件目录 + Directory.Delete(tempFilePath, true); + throw; } - - return await OssObjectAppService.CreateAsync(createOssObjectInput); } [HttpDelete] [Route("bulk-delete")] - public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input) + public virtual async Task BulkDeleteAsync([FromBody] BulkDeleteOssObjectInput input) { await OssObjectAppService.BulkDeleteAsync(input); } diff --git a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/UploadOssObjectInput.cs b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/UploadOssObjectInput.cs index 856e44c5a..972bf4510 100644 --- a/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/UploadOssObjectInput.cs +++ b/aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/UploadOssObjectInput.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using System.ComponentModel.DataAnnotations; namespace LINGYUN.Abp.FileManagement { @@ -6,7 +7,41 @@ namespace LINGYUN.Abp.FileManagement { public string Bucket { get; set; } public string Path { get; set; } - public string Name { get; set; } + + #region 配合Uplaoder 分块传输 + /// + /// 文件名 + /// + [Required] + public string FileName { get; set; } + /// + /// 常规块大小 + /// + [Required] + public int ChunkSize { get; set; } + /// + /// 当前块大小 + /// + [Required] + public int CurrentChunkSize { get; set; } + /// + /// 当前上传中块的索引 + /// + [Required] + public int ChunkNumber { get; set; } + /// + /// 块总数 + /// + [Required] + public int TotalChunks { get; set; } + /// + /// 总文件大小 + /// + [Required] + public int TotalSize { get; set; } + + #endregion + public IFormFile File { get; set; } } } diff --git a/vueJs/src/api/oss-manager.ts b/vueJs/src/api/oss-manager.ts index 517e9d9c2..2a02a7af2 100644 --- a/vueJs/src/api/oss-manager.ts +++ b/vueJs/src/api/oss-manager.ts @@ -5,7 +5,7 @@ import { urlStringify } from '@/utils/index' const serviceUrl = process.env.VUE_APP_BASE_API const containerUrl = '/api/file-management/containes' const objectUrl = '/api/file-management/objects' -export const objectUploadUrl = objectUrl + '/upload' +export const objectUploadUrl = serviceUrl + objectUrl + '/upload' export const staticUrl = '/api/files/static/' export default class OssManager { @@ -29,7 +29,7 @@ export default class OssManager { return ApiService.Delete(_url, serviceUrl) } - public static createFolder(bucket: string, name: string, path: string = "") { + public static createFolder(bucket: string, name: string, path: string = '') { const input = { bucket: bucket, object: name, @@ -43,7 +43,7 @@ export default class OssManager { return ApiService.Get(_url, serviceUrl) } - public static getObject(bucket: string, object: string, path: string = "") { + public static getObject(bucket: string, object: string, path: string = '') { let _url = objectUrl + '?bucket=' + bucket + '&object=' + object if (path) { _url += '&path=' + path @@ -51,31 +51,53 @@ export default class OssManager { return ApiService.Get(_url, serviceUrl) } - public static getObjectData(bucket: string, object: string, path: string = "") { - let _url = staticUrl + bucket + '/' - if (path) { - // 某些情况下要对 / 编码 - _url += '/p/' + path.replace('/', '%2F') - if (_url.endsWith('%2F')) { - _url = _url.substring(0, _url.length - 3) + '/' - } - } - _url += object + public static getObjectData(bucket: string, object: string, path: string = '') { return ApiService.HttpRequest({ - url: _url, + url: this.generateOssUrl(bucket, object, path), baseURL: serviceUrl, method: 'GET', responseType: 'blob' }) } - public static deleteObject(bucket: string, object: string, path: string = "") { + public static deleteObject(bucket: string, object: string, path: string = '') { let _url = objectUrl + '?bucket=' + bucket + '&object=' + object if (path) { _url += '&path=' + path } return ApiService.Delete(_url, serviceUrl) } + + public static bulkDeleteObject(bucket: string, objects: string[], path: string = '') { + const _url = objectUrl + '/bulk-delete' + return ApiService + .HttpRequest({ + url: _url, + baseURL: serviceUrl, + method: 'DELETE', + data: { + bucket: bucket, + path: path, + objects: objects + } + }) + } + + public static generateOssUrl(bucket: string, object: string, path: string = '', prefix: string = '') { + let _url = staticUrl + bucket + '/' + if (path) { + // 某些情况下要对 / 编码 + _url += '/p/' + path.replace('/', '%2F') + if (_url.endsWith('%2F')) { + _url = _url.substring(0, _url.length - 3) + '/' + } + } + _url += object + if (prefix) { + _url = prefix + _url + } + return _url + } } export class GetOssContainerRequest extends PagedAndSortedResultRequestDto { diff --git a/vueJs/src/views/oss-management/components/OssObjectUploadDialog.vue b/vueJs/src/views/oss-management/components/OssObjectUploadDialog.vue new file mode 100644 index 000000000..bbb0d7d5b --- /dev/null +++ b/vueJs/src/views/oss-management/components/OssObjectUploadDialog.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/vueJs/src/views/oss-management/index.vue b/vueJs/src/views/oss-management/index.vue index 1dd052413..1edb0b9d4 100644 --- a/vueJs/src/views/oss-management/index.vue +++ b/vueJs/src/views/oss-management/index.vue @@ -157,6 +157,15 @@ :path="selectionOssObject.path" @closed="showOssObject=false" /> + + @@ -171,6 +180,7 @@ import OssManagerApi, { import { dateFormat } from '@/utils/index' import { checkPermission } from '@/utils/permission' import OssObjectProfile from './components/OssObjectProfile.vue' +import OssObjectUploadDialog from './components/OssObjectUploadDialog.vue' const kbUnit = 1 * 1024 const mbUnit = kbUnit * 1024 @@ -180,7 +190,8 @@ const $contextmenu = Vue.prototype.$contextmenu @Component({ name: 'OssManagement', components: { - OssObjectProfile + OssObjectProfile, + OssObjectUploadDialog }, methods: { checkPermission @@ -226,6 +237,9 @@ export default class OssManagement extends Vue { private objects = new Array() private fileSystemRoot = new Array() + private showUploadOss = false + private uploadPath = '' + private getObjectRequest = new GetOssObjectRequest() private getBucketRequest = new GetOssContainerRequest() @@ -330,6 +344,7 @@ export default class OssManagement extends Vue { .deleteObject(this.bucket, oss.name, oss.path) .then(() => { this.$notify.success(this.l('global.dataHasBeenDeleted', { name: oss.name })) + this.handleClearObjects() this.handleGetObjects() }) } @@ -343,11 +358,14 @@ export default class OssManagement extends Vue { } private handleDownloadOssObject(oss: OssObject) { - console.log(oss) - } - - private handleFileSystemCommand(command: any) { - console.log(command) + if (!oss.isFolder) { + const link = document.createElement('a') + link.style.display = 'none' + link.href = OssManagerApi.generateOssUrl(this.bucket, oss.name, oss.path, '/api/') + link.setAttribute('download', oss.name) + document.body.appendChild(link) + link.click() + } } private handleClearObjects() { @@ -364,11 +382,6 @@ export default class OssManagement extends Vue { label: this.$t('fileSystem.addFolder'), disabled: !checkPermission(['AbpFileManagement.FileSystem.Create']), onClick: () => { - let parent = '' - // 在根目录下 - if (this.fileSystemRoot.length > 1) { - parent = this.fileSystemRoot.slice(1).join('') - } this.$prompt(this.$t('global.pleaseInputBy', { key: this.$t('fileSystem.name') }).toString(), this.$t('fileSystem.addFolder').toString(), { showInput: true, @@ -380,7 +393,7 @@ export default class OssManagement extends Vue { }).then((val: any) => { const name = val.value + '/' OssManagerApi - .createFolder(this.bucket, name.replace('//', '/'), parent) + .createFolder(this.bucket, name.replace('//', '/'), this.getCurrentPath()) .then(res => { this.$message.success(this.$t('fileSystem.folderCreateSuccess', { name: res.name }).toString()) this.handleClearObjects() @@ -394,28 +407,25 @@ export default class OssManagement extends Vue { label: this.$t('fileSystem.upload'), disabled: !checkPermission(['AbpFileManagement.FileSystem.FileManager.Create']), onClick: () => { - let path = '' - if (this.fileSystemRoot.length > 1) { - path = this.fileSystemRoot.slice(1).join('/') - } + this.uploadPath = this.getCurrentPath() + this.showUploadOss = true }, divided: true }, - { - label: this.$t('fileSystem.bacthDownload'), - disabled: !checkPermission(['AbpFileManagement.FileSystem.FileManager.Download']), - onClick: () => { - const table = this.$refs.ossObjectTable as any - } - }, { label: this.$t('fileSystem.bacthDelete'), - disabled: true, // !checkPermission(['AbpFileManagement.FileSystem.FileManager.Delete']), + disabled: !checkPermission(['AbpFileManagement.FileSystem.FileManager.Delete']), onClick: () => { // 未公布批量删除接口 - // const table = this.$refs.ossObjectTable as any - // 过滤类型为文件的选中项 - // const selectFiles = table.selection.filter((x: any) => x.type === 1) + const table = this.$refs.ossObjectTable as any + console.log(table) + OssManagerApi + .bulkDeleteObject(this.bucket, table.selection.map((x: any) => x.name), this.getCurrentPath()) + .then(() => { + this.$message.success(this.l('successful')) + this.handleClearObjects() + this.handleGetObjects() + }) } } ], @@ -427,6 +437,20 @@ export default class OssManagement extends Vue { return false } + private onFileUploaded() { + this.$message.success(this.l('fileSystem.uploadSuccess')) + this.handleClearObjects() + this.handleGetObjects() + } + + private getCurrentPath() { + let path = '' + if (this.fileSystemRoot.length > 1) { + path = this.fileSystemRoot.slice(1).join('') + } + return path + } + private l(name: string, values?: any[] | { [key: string]: any }) { return this.$t(name, values).toString() }