30 changed files with 497 additions and 1094 deletions
@ -1,31 +1,3 @@ |
|||||
# LINGYUN.Abp.Aliyun |
# Oss-Management |
||||
|
|
||||
阿里云sdk集成 |
File-Management更名为Oss-Management |
||||
|
|
||||
参照: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字符串 |
|
||||
|
|
||||
## 其他 |
|
||||
|
|
||||
网络因素在高并发下可能会出现预期外的异常,考虑使用二级缓存 |
|
||||
|
|||||
@ -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; } |
|
||||
} |
|
||||
} |
|
||||
@ -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 |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 文件名
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
[StringLength(255)] |
|
||||
public string FileName { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 文件路径
|
|
||||
/// </summary>
|
|
||||
[StringLength(255)] |
|
||||
public string Path { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 文件数据,前端无需传递此参数,由控制器传递
|
|
||||
/// </summary>
|
|
||||
[DisableAuditing] |
|
||||
[DisableValidation]// TODO: 需要禁用参数检查,否则会有一个框架方面的性能问题存在
|
|
||||
public byte[] Data { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 是否覆盖文件
|
|
||||
/// </summary>
|
|
||||
public bool Rewrite { get; set; } = false; |
|
||||
} |
|
||||
} |
|
||||
@ -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; } |
|
||||
} |
|
||||
} |
|
||||
@ -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 |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 当前字节数
|
|
||||
/// </summary>
|
|
||||
public int CurrentByte { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -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; } |
|
||||
} |
|
||||
} |
|
||||
@ -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; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,8 +0,0 @@ |
|||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
public enum FileSystemType |
|
||||
{ |
|
||||
Folder = 0, |
|
||||
File = 1 |
|
||||
} |
|
||||
} |
|
||||
@ -1,11 +0,0 @@ |
|||||
using System.ComponentModel.DataAnnotations; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
public class FileSystemUpdateDto |
|
||||
{ |
|
||||
[Required] |
|
||||
[StringLength(255)] |
|
||||
public string NewName { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,11 +0,0 @@ |
|||||
using System.ComponentModel.DataAnnotations; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
public class FolderCopyDto |
|
||||
{ |
|
||||
[Required] |
|
||||
[StringLength(255)] |
|
||||
public string CopyToPath { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -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; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,11 +0,0 @@ |
|||||
using System.ComponentModel.DataAnnotations; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
public class FolderMoveDto |
|
||||
{ |
|
||||
[Required] |
|
||||
[StringLength(255)] |
|
||||
public string MoveToPath { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -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; } |
|
||||
} |
|
||||
} |
|
||||
@ -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<FileSystemDto> GetAsync(FileSystemGetDto input); |
|
||||
|
|
||||
Task<PagedResultDto<FileSystemDto>> GetListAsync(GetFileSystemListDto input); |
|
||||
|
|
||||
Task CreateFolderAsync(FolderCreateDto input); |
|
||||
|
|
||||
Task<FileSystemDto> 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<Stream> DownloadFileAsync(FileSystemGetDto input); |
|
||||
} |
|
||||
} |
|
||||
@ -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<AbpFileManagementContainer> BlobContainer { get; } |
|
||||
protected IBlobContainerConfigurationProvider BlobContainerConfigurationProvider { get; } |
|
||||
public FileSystemAppService( |
|
||||
IBlobContainer<AbpFileManagementContainer> 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<Stream> 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<FileSystemDto> 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<PagedResultDto<FileSystemDto>> GetListAsync(GetFileSystemListDto input) |
|
||||
{ |
|
||||
List<FileSystemDto> fileSystems = new List<FileSystemDto>(); |
|
||||
|
|
||||
string fileSystemPath = GetFileSystemBashPath(); |
|
||||
if (!input.Parent.IsNullOrWhiteSpace()) |
|
||||
{ |
|
||||
fileSystemPath = GetFileSystemPath(input.Parent); |
|
||||
} |
|
||||
var directoryInfo = new DirectoryInfo(fileSystemPath); |
|
||||
if (!directoryInfo.Exists) |
|
||||
{ |
|
||||
return Task.FromResult(new PagedResultDto<FileSystemDto>(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<FileSystemDto>( |
|
||||
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<FileSystemDto> 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"]); |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 获取文件系统相对路径
|
|
||||
/// </summary>
|
|
||||
/// <param name="path"></param>
|
|
||||
/// <returns></returns>
|
|
||||
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<AbpFileManagementContainer>(); |
|
||||
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; |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 获取合并的文件路径
|
|
||||
/// </summary>
|
|
||||
/// <param name="path"></param>
|
|
||||
/// <returns></returns>
|
|
||||
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; |
|
||||
} |
|
||||
/// <summary>
|
|
||||
/// 获取文件系统存储路径
|
|
||||
/// </summary>
|
|
||||
/// <returns></returns>
|
|
||||
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<AbpFileManagementContainer>(); |
|
||||
|
|
||||
blobPath = Path.Combine(blobPath, containerName); |
|
||||
|
|
||||
if (!Directory.Exists(blobPath)) |
|
||||
{ |
|
||||
Directory.CreateDirectory(blobPath); |
|
||||
} |
|
||||
|
|
||||
return blobPath; |
|
||||
} |
|
||||
|
|
||||
protected virtual FileSystemBlobProviderConfiguration GetFileSystemBlobProviderConfiguration() |
|
||||
{ |
|
||||
var blobConfiguration = BlobContainerConfigurationProvider |
|
||||
.Get<AbpFileManagementContainer>(); |
|
||||
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); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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<IActionResult> 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<FileSystemDto> GetAsync(FileSystemGetDto input) |
|
||||
{ |
|
||||
return await FileSystemAppService.GetAsync(input); |
|
||||
} |
|
||||
|
|
||||
[HttpGet] |
|
||||
public virtual async Task<PagedResultDto<FileSystemDto>> 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<FileSystemDto> UpdateAsync([Required, StringLength(255)] string name, FileSystemUpdateDto input) |
|
||||
{ |
|
||||
return await FileSystemAppService.UpdateAsync(name, input); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,35 +0,0 @@ |
|||||
using Microsoft.AspNetCore.Http; |
|
||||
using System.ComponentModel.DataAnnotations; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
public class FileUploadDto : FileCreateDto |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 常规块大小
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public int ChunkSize { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 当前块大小
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public int CurrentChunkSize { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 当前上传中块的索引
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public int ChunkNumber { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 块总数
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public int TotalChunks { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 总文件大小
|
|
||||
/// </summary>
|
|
||||
[Required] |
|
||||
public int TotalSize { get; set; } |
|
||||
public IFormFile File { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -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<AbpFileManagementResource> 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<FileValidation> GetByCacheItemAsync() |
||||
|
{ |
||||
|
var fileValidation = _cache.Get<FileValidation>(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<FileValidation> 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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.FileManagement |
||||
|
{ |
||||
|
public interface IFileValidater |
||||
|
{ |
||||
|
Task ValidationAsync(UploadOssObjectInput input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,131 @@ |
|||||
|
<template> |
||||
|
<el-dialog |
||||
|
:title="$t('fileSystem.upload')" |
||||
|
:visible="showDialog" |
||||
|
custom-class="modal-form" |
||||
|
@close="onFormClosed" |
||||
|
> |
||||
|
<uploader |
||||
|
ref="uploader" |
||||
|
:options="options" |
||||
|
:auto-start="false" |
||||
|
class="uploader-pane" |
||||
|
@file-added="onFileAdded" |
||||
|
@file-error="onFileError" |
||||
|
@file-complete="onFileUploadCompleted" |
||||
|
> |
||||
|
<uploader-unsupport /> |
||||
|
<uploader-drop> |
||||
|
<uploader-btn :attrs="attrs"> |
||||
|
{{ $t('fileSystem.addFile') }} |
||||
|
</uploader-btn> |
||||
|
</uploader-drop> |
||||
|
<uploader-list /> |
||||
|
</uploader> |
||||
|
</el-dialog> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { Component, Vue, Prop, Watch } from 'vue-property-decorator' |
||||
|
import { objectUploadUrl } from '@/api/oss-manager' |
||||
|
import { UserModule } from '@/store/modules/user' |
||||
|
|
||||
|
export class UploadOptions { |
||||
|
target!: string |
||||
|
chunkSize!: number |
||||
|
testChunks!: boolean |
||||
|
fileParameterName!: string |
||||
|
maxChunkRetries!: number |
||||
|
headers?: any |
||||
|
query?: any |
||||
|
permanentErrors?: number[] |
||||
|
successStatuses?: number[] |
||||
|
|
||||
|
constructor() { |
||||
|
this.query = {} |
||||
|
this.headers = {} |
||||
|
this.testChunks = false |
||||
|
this.successStatuses = new Array<number>() |
||||
|
this.permanentErrors = new Array<number>() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Component({ |
||||
|
name: 'OssObjectUploadDialog' |
||||
|
}) |
||||
|
export default class extends Vue { |
||||
|
@Prop({ default: () => new UploadOptions() }) |
||||
|
private options!: UploadOptions |
||||
|
|
||||
|
@Prop({ default: '' }) |
||||
|
private bucket!: string |
||||
|
|
||||
|
@Prop({ default: '' }) |
||||
|
private path!: string |
||||
|
|
||||
|
@Prop({ default: false }) |
||||
|
private showDialog!: boolean |
||||
|
|
||||
|
private attrs!: {[key: string]: any} |
||||
|
private files?: any = {} |
||||
|
|
||||
|
constructor() { |
||||
|
super() |
||||
|
this.attrs = { |
||||
|
accept: ['image/*', 'document/*', 'video/*', 'audio/*'] |
||||
|
} |
||||
|
this.options.target = objectUploadUrl |
||||
|
this.options.successStatuses = [200, 201, 202, 204, 205] |
||||
|
this.options.permanentErrors = [400, 401, 403, 404, 415, 500, 501] |
||||
|
this.options.headers.Authorization = UserModule.token |
||||
|
} |
||||
|
|
||||
|
public close() { |
||||
|
this.files = {} |
||||
|
const uploadControl = this.$refs.uploader as any |
||||
|
uploadControl.files = [] |
||||
|
uploadControl.fileList = [] |
||||
|
uploadControl.uploader.cancel() |
||||
|
} |
||||
|
|
||||
|
@Watch('bucket', { immediate: true }) |
||||
|
private onBucketChanged() { |
||||
|
this.options.query.bucket = this.bucket |
||||
|
} |
||||
|
|
||||
|
@Watch('path', { immediate: true }) |
||||
|
private onPathChanged() { |
||||
|
this.options.query.path = this.path |
||||
|
} |
||||
|
|
||||
|
private onFileAdded(file: any) { |
||||
|
this.files[file.name] = file.chunkSize |
||||
|
file.uploader.fileStatusText.error = this.$t('fileSystem.uploadError') |
||||
|
file.uploader.fileStatusText.paused = this.$t('fileSystem.paused') |
||||
|
file.uploader.fileStatusText.success = this.$t('fileSystem.uploadSuccess') |
||||
|
file.uploader.fileStatusText.waiting = this.$t('fileSystem.waitingUpload') |
||||
|
file.uploader.fileStatusText.uploading = this.$t('fileSystem.uploading') |
||||
|
} |
||||
|
|
||||
|
private onFileError(rootFile: any, file: any, message: any) { |
||||
|
const abpResponse = JSON.parse(message) |
||||
|
this.$message.error(abpResponse.error.message) |
||||
|
} |
||||
|
|
||||
|
private onFileUploadCompleted(file: any) { |
||||
|
const uploadControl = this.$refs.uploader as any |
||||
|
if (uploadControl && uploadControl.uploader) { |
||||
|
uploadControl.uploader.removeFile(file) |
||||
|
} |
||||
|
this.$emit('onFileUploaded', file.name) |
||||
|
} |
||||
|
|
||||
|
private onFormClosed() { |
||||
|
this.$emit('closed') |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
|
||||
|
</style> |
||||
Loading…
Reference in new issue