committed by
GitHub
156 changed files with 6901 additions and 1575 deletions
File diff suppressed because one or more lines are too long
@ -1,12 +0,0 @@ |
|||||
using Volo.Abp.Application; |
|
||||
using Volo.Abp.Modularity; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
[DependsOn( |
|
||||
typeof(AbpFileManagementDomainSharedModule), |
|
||||
typeof(AbpDddApplicationModule))] |
|
||||
public class AbpFileManagementApplicationContractsModule : AbpModule |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
@ -1,49 +0,0 @@ |
|||||
using LINGYUN.Abp.FileManagement.Localization; |
|
||||
using Volo.Abp.Features; |
|
||||
using Volo.Abp.Localization; |
|
||||
using Volo.Abp.Validation.StringValues; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement.Features |
|
||||
{ |
|
||||
public class AbpFileManagementFeatureDefinitionProvider : FeatureDefinitionProvider |
|
||||
{ |
|
||||
public override void Define(IFeatureDefinitionContext context) |
|
||||
{ |
|
||||
var featureGroup = context.AddGroup( |
|
||||
name: AbpFileManagementFeatureNames.GroupName, |
|
||||
displayName: L("Features:FileManagement")); |
|
||||
|
|
||||
var fileSystemFeature = featureGroup.AddFeature( |
|
||||
name: AbpFileManagementFeatureNames.FileSystem.Default, |
|
||||
displayName: L("Features:DisplayName:FileSystem"), |
|
||||
description: L("Features:Description:FileSystem")); |
|
||||
|
|
||||
fileSystemFeature.CreateChild( |
|
||||
name: AbpFileManagementFeatureNames.FileSystem.DownloadFile, |
|
||||
defaultValue: false.ToString(), |
|
||||
displayName: L("Features:DisplayName:DownloadFile"), |
|
||||
description: L("Features:Description:DownloadFile"), |
|
||||
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
|
||||
|
|
||||
fileSystemFeature.CreateChild( |
|
||||
name: AbpFileManagementFeatureNames.FileSystem.UploadFile, |
|
||||
defaultValue: true.ToString(), |
|
||||
displayName: L("Features:DisplayName:UploadFile"), |
|
||||
description: L("Features:Description:UploadFile"), |
|
||||
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
|
||||
|
|
||||
// TODO: 此功能需要控制器协同,暂时不实现
|
|
||||
fileSystemFeature.CreateChild( |
|
||||
name: AbpFileManagementFeatureNames.FileSystem.MaxUploadFileCount, |
|
||||
defaultValue: 1.ToString(), |
|
||||
displayName: L("Features:DisplayName:MaxUploadFileCount"), |
|
||||
description: L("Features:Description:MaxUploadFileCount"), |
|
||||
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 10))); |
|
||||
} |
|
||||
|
|
||||
protected ILocalizableString L(string name) |
|
||||
{ |
|
||||
return LocalizableString.Create<AbpFileManagementResource>(name); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,23 +0,0 @@ |
|||||
namespace LINGYUN.Abp.FileManagement.Features |
|
||||
{ |
|
||||
public class AbpFileManagementFeatureNames |
|
||||
{ |
|
||||
public const string GroupName = "Abp.FileManagement"; |
|
||||
public class FileSystem |
|
||||
{ |
|
||||
public const string Default = GroupName + ".FileSystem"; |
|
||||
/// <summary>
|
|
||||
/// 下载文件功能
|
|
||||
/// </summary>
|
|
||||
public const string DownloadFile = Default + ".DownloadFile"; |
|
||||
/// <summary>
|
|
||||
/// 上传文件功能
|
|
||||
/// </summary>
|
|
||||
public const string UploadFile = Default + ".UploadFile"; |
|
||||
/// <summary>
|
|
||||
/// 最大上传文件
|
|
||||
/// </summary>
|
|
||||
public const string MaxUploadFileCount = Default + ".MaxUploadFileCount"; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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,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,34 +0,0 @@ |
|||||
using LINGYUN.Abp.FileManagement.Localization; |
|
||||
using Volo.Abp.Authorization.Permissions; |
|
||||
using Volo.Abp.Localization; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement.Permissions |
|
||||
{ |
|
||||
public class AbpFileManagementPermissionDefinitionProvider : PermissionDefinitionProvider |
|
||||
{ |
|
||||
public override void Define(IPermissionDefinitionContext context) |
|
||||
{ |
|
||||
var fileManagement = context.AddGroup(AbpFileManagementPermissions.GroupName, L("Permission:FileManagement")); |
|
||||
|
|
||||
var fileSystem = fileManagement.AddPermission(AbpFileManagementPermissions.FileSystem.Default, L("Permission:FileSystem")); |
|
||||
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Create, L("Permission:CreateFolder")); |
|
||||
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Delete, L("Permission:DeleteFolder")); |
|
||||
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Update, L("Permission:UpdateFolder")); |
|
||||
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Copy, L("Permission:CopyFolder")); |
|
||||
fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.Move, L("Permission:MoveFolder")); |
|
||||
|
|
||||
var fileManager = fileSystem.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Default, L("Permission:FileManager")); |
|
||||
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Create, L("Permission:AppendFile")); |
|
||||
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Update, L("Permission:UpdateFile")); |
|
||||
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Delete, L("Permission:DeleteFile")); |
|
||||
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Copy, L("Permission:CopyFile")); |
|
||||
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Move, L("Permission:MoveFile")); |
|
||||
fileManager.AddChild(AbpFileManagementPermissions.FileSystem.FileManager.Download, L("Permission:DownloadFile")); |
|
||||
} |
|
||||
|
|
||||
private static LocalizableString L(string name) |
|
||||
{ |
|
||||
return LocalizableString.Create<AbpFileManagementResource>(name); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,44 +0,0 @@ |
|||||
namespace LINGYUN.Abp.FileManagement.Permissions |
|
||||
{ |
|
||||
public class AbpFileManagementPermissions |
|
||||
{ |
|
||||
public const string GroupName = "AbpFileManagement"; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// 文件系统
|
|
||||
/// </summary>
|
|
||||
public class FileSystem |
|
||||
{ |
|
||||
public const string Default = GroupName + ".FileSystem"; |
|
||||
|
|
||||
public const string Create = Default + ".Create"; |
|
||||
|
|
||||
public const string Delete = Default + ".Delete"; |
|
||||
|
|
||||
public const string Update = Default + ".Update"; |
|
||||
|
|
||||
public const string Copy = Default + ".Copy"; |
|
||||
|
|
||||
public const string Move = Default + ".Move"; |
|
||||
/// <summary>
|
|
||||
/// 文件管理
|
|
||||
/// </summary>
|
|
||||
public class FileManager |
|
||||
{ |
|
||||
public const string Default = FileSystem.Default + ".FileManager"; |
|
||||
|
|
||||
public const string Create = Default + ".Create"; |
|
||||
|
|
||||
public const string Copy = Default + ".Copy"; |
|
||||
|
|
||||
public const string Delete = Default + ".Delete"; |
|
||||
|
|
||||
public const string Update = Default + ".Update"; |
|
||||
|
|
||||
public const string Move = Default + ".Move"; |
|
||||
|
|
||||
public const string Download = Default + ".Download"; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,15 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<Import Project="..\..\..\common.props" /> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFramework>netstandard2.0</TargetFramework> |
|
||||
<RootNamespace /> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Application.Contracts\LINGYUN.Abp.FileManagement.Application.Contracts.csproj" /> |
|
||||
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Domain\LINGYUN.Abp.FileManagement.Domain.csproj" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,12 +0,0 @@ |
|||||
using Volo.Abp.Modularity; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
[DependsOn( |
|
||||
typeof(AbpFileManagementDomainModule), |
|
||||
typeof(AbpFileManagementApplicationContractsModule))] |
|
||||
public class AbpFileManagementApplicationModule : AbpModule |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -1,13 +0,0 @@ |
|||||
using LINGYUN.Abp.FileManagement.Localization; |
|
||||
using Volo.Abp.Application.Services; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
public class FileManagementApplicationServiceBase : ApplicationService |
|
||||
{ |
|
||||
protected FileManagementApplicationServiceBase() |
|
||||
{ |
|
||||
LocalizationResource = typeof(AbpFileManagementResource); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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<FileSystemContainer> BlobContainer { get; } |
|
||||
protected IBlobContainerConfigurationProvider BlobContainerConfigurationProvider { get; } |
|
||||
public FileSystemAppService( |
|
||||
IBlobContainer<FileSystemContainer> 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<FileSystemContainer>(); |
|
||||
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<FileSystemContainer>(); |
|
||||
|
|
||||
blobPath = Path.Combine(blobPath, containerName); |
|
||||
|
|
||||
if (!Directory.Exists(blobPath)) |
|
||||
{ |
|
||||
Directory.CreateDirectory(blobPath); |
|
||||
} |
|
||||
|
|
||||
return blobPath; |
|
||||
} |
|
||||
|
|
||||
protected virtual FileSystemBlobProviderConfiguration GetFileSystemBlobProviderConfiguration() |
|
||||
{ |
|
||||
var blobConfiguration = BlobContainerConfigurationProvider |
|
||||
.Get<FileSystemContainer>(); |
|
||||
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,30 +0,0 @@ |
|||||
using LINGYUN.Abp.FileManagement.Localization; |
|
||||
using Volo.Abp.Localization; |
|
||||
using Volo.Abp.Modularity; |
|
||||
using Volo.Abp.Validation; |
|
||||
using Volo.Abp.Validation.Localization; |
|
||||
using Volo.Abp.VirtualFileSystem; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
[DependsOn(typeof(AbpValidationModule))] |
|
||||
public class AbpFileManagementDomainSharedModule : AbpModule |
|
||||
{ |
|
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
|
||||
{ |
|
||||
Configure<AbpVirtualFileSystemOptions>(options => |
|
||||
{ |
|
||||
options.FileSets.AddEmbedded<AbpFileManagementDomainSharedModule>(); |
|
||||
}); |
|
||||
|
|
||||
Configure<AbpLocalizationOptions>(options => |
|
||||
{ |
|
||||
options.Resources |
|
||||
.Add<AbpFileManagementResource>("en") |
|
||||
.AddBaseTypes( |
|
||||
typeof(AbpValidationResource) |
|
||||
).AddVirtualJson("/LINGYUN/Abp/FileManagement/Localization/Resources"); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,9 +0,0 @@ |
|||||
using Volo.Abp.Localization; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement.Localization |
|
||||
{ |
|
||||
[LocalizationResourceName("AbpFileManagement")] |
|
||||
public class AbpFileManagementResource |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
@ -1,39 +0,0 @@ |
|||||
{ |
|
||||
"culture": "en", |
|
||||
"texts": { |
|
||||
"Permission:FileManagement": "File management", |
|
||||
"Permission:FileSystem": "File system", |
|
||||
"Permission:FileManager": "Files", |
|
||||
"Permission:CreateFolder": "Create directory", |
|
||||
"Permission:DeleteFolder": "Delete directory", |
|
||||
"Permission:UpdateFolder": "Edit directory", |
|
||||
"Permission:MoveFolder": "Change directory", |
|
||||
"Permission:CopyFolder": "Copy directory", |
|
||||
"Permission:AppendFile": "Add files", |
|
||||
"Permission:UpdateFile": "Change file", |
|
||||
"Permission:DeleteFile": "Delete file", |
|
||||
"Permission:CopyFile": "Copy file", |
|
||||
"Permission:MoveFile": "Move file", |
|
||||
"Permission:DownloadFile": "Download file", |
|
||||
"FileNotFound": "The specified file does not exist!", |
|
||||
"PathNotFound": "The specified directory does not exist!", |
|
||||
"FilePathNotFound": "The file or directory does not exist!", |
|
||||
"PathAlreadyExists": "The specified directory already exists!", |
|
||||
"PathCannotBeDeletedWithNotEmpty": "The specified directory is not empty and cannot be deleted!", |
|
||||
"FilePathAlreadyExists": "The same file or directory already exists in the specified path!", |
|
||||
"UploadFileSizeBeyondLimit": "Upload file size cannot exceed {0} MB!", |
|
||||
"NotAllowedFileExtensionName": "Not allowed file extension: {0}!", |
|
||||
"DisplayName:FileLimitLength": "File limit size", |
|
||||
"Description:FileLimitLength": "Limit size of uploaded file in MB", |
|
||||
"DisplayName:AllowFileExtensions": "File extension", |
|
||||
"Description:AllowFileExtensions": "List of allowed extensions to upload files, with multiple extensions separated by, don't need a notation", |
|
||||
"Features:FileManagement": "File management", |
|
||||
"Features:DisplayName:FileSystem": "File system", |
|
||||
"Features:DisplayName:DownloadFile": "Download file", |
|
||||
"Features:Description:DownloadFile": "Whether to allow users to download files", |
|
||||
"Features:DisplayName:UploadFile": "Upload file", |
|
||||
"Features:Description:UploadFile": "Whether to allow users to upload files", |
|
||||
"Features:DisplayName:MaxUploadFileCount": "Maximum number of upload files", |
|
||||
"Features:Description:MaxUploadFileCount": "Limit the number of files a user uploads at a time" |
|
||||
} |
|
||||
} |
|
||||
@ -1,39 +0,0 @@ |
|||||
{ |
|
||||
"culture": "zh-Hans", |
|
||||
"texts": { |
|
||||
"Permission:FileManagement": "文件管理", |
|
||||
"Permission:FileSystem": "文件系统", |
|
||||
"Permission:FileManager": "文件", |
|
||||
"Permission:CreateFolder": "创建目录", |
|
||||
"Permission:DeleteFolder": "删除目录", |
|
||||
"Permission:UpdateFolder": "修改目录", |
|
||||
"Permission:MoveFolder": "变更目录", |
|
||||
"Permission:CopyFolder": "复制目录", |
|
||||
"Permission:AppendFile": "添加文件", |
|
||||
"Permission:UpdateFile": "变更文件", |
|
||||
"Permission:DeleteFile": "删除文件", |
|
||||
"Permission:CopyFile": "复制文件", |
|
||||
"Permission:MoveFile": "移动文件", |
|
||||
"Permission:DownloadFile": "下载文件", |
|
||||
"FileNotFound": "指定的文件不存在!", |
|
||||
"PathNotFound": "指定的目录不存在!", |
|
||||
"FilePathNotFound": "文件或目录不存在!", |
|
||||
"PathAlreadyExists": "指定的目录已经存在!", |
|
||||
"PathCannotBeDeletedWithNotEmpty": "指定的目录不为空,不可删除此目录!", |
|
||||
"FilePathAlreadyExists": "指定的路径中已经有相同的文件或目录存在!", |
|
||||
"UploadFileSizeBeyondLimit": "上传文件大小不能超过 {0} MB!", |
|
||||
"NotAllowedFileExtensionName": "不被允许的文件扩展名: {0}!", |
|
||||
"DisplayName:FileLimitLength": "文件限制大小", |
|
||||
"Description:FileLimitLength": "上传文件的限制大小,单位(MB)", |
|
||||
"DisplayName:AllowFileExtensions": "文件扩展名", |
|
||||
"Description:AllowFileExtensions": "允许的上传文件扩展名列表,多个扩展名以,分隔,无需输入.符号", |
|
||||
"Features:FileManagement": "文件管理", |
|
||||
"Features:DisplayName:FileSystem": "文件系统", |
|
||||
"Features:DisplayName:DownloadFile": "下载文件", |
|
||||
"Features:Description:DownloadFile": "是否允许用户下载文件", |
|
||||
"Features:DisplayName:UploadFile": "上传文件", |
|
||||
"Features:Description:UploadFile": "是否允许用户上传文件", |
|
||||
"Features:DisplayName:MaxUploadFileCount": "上传文件数量", |
|
||||
"Features:Description:MaxUploadFileCount": "用户单次上传文件的限制数量" |
|
||||
} |
|
||||
} |
|
||||
@ -1,18 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<Import Project="..\..\..\common.props" /> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFramework>netstandard2.0</TargetFramework> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="Volo.Abp.BlobStoring.FileSystem" Version="4.2.1" /> |
|
||||
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="4.2.1" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Domain.Shared\LINGYUN.Abp.FileManagement.Domain.Shared.csproj" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,15 +0,0 @@ |
|||||
using Volo.Abp.Domain; |
|
||||
using Volo.Abp.Modularity; |
|
||||
using Volo.Abp.MultiTenancy; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
[DependsOn( |
|
||||
typeof(AbpDddDomainModule), |
|
||||
typeof(AbpMultiTenancyModule), |
|
||||
typeof(AbpFileManagementDomainSharedModule) |
|
||||
)] |
|
||||
public class AbpFileManagementDomainModule : AbpModule |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
@ -1,9 +0,0 @@ |
|||||
using Volo.Abp.BlobStoring; |
|
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
|
||||
{ |
|
||||
[BlobContainerName("abp-file-management")] |
|
||||
public class FileSystemContainer |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
@ -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); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,14 @@ |
|||||
|
namespace LINGYUN.Abp.Identity |
||||
|
{ |
||||
|
public static class ExtensionIdentityUserConsts |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 头像字段
|
||||
|
/// </summary>
|
||||
|
public static string AvatarUrlField { get; set; } = "AvatarUrl"; |
||||
|
/// <summary>
|
||||
|
/// 头像字段最大长度
|
||||
|
/// </summary>
|
||||
|
public static int MaxAvatarUrlLength { get; set; } = 128; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\common\LINGYUN.Abp.BlobStoring.Aliyun\LINGYUN.Abp.BlobStoring.Aliyun.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Domain\LINGYUN.Abp.OssManagement.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,17 @@ |
|||||
|
using LINGYUN.Abp.BlobStoring.Aliyun; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement.Aliyun |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpBlobStoringAliyunModule), |
||||
|
typeof(AbpOssManagementDomainModule))] |
||||
|
public class AbpOssManagementAliyunModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddTransient<IOssContainerFactory, AliyunOssContainerFactory>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,369 @@ |
|||||
|
using Aliyun.OSS; |
||||
|
using LINGYUN.Abp.BlobStoring.Aliyun; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement.Aliyun |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Oss容器的阿里云实现
|
||||
|
/// </summary>
|
||||
|
internal class AliyunOssContainer : IOssContainer |
||||
|
{ |
||||
|
protected ICurrentTenant CurrentTenant { get; } |
||||
|
protected IOssClientFactory OssClientFactory { get; } |
||||
|
public AliyunOssContainer( |
||||
|
ICurrentTenant currentTenant, |
||||
|
IOssClientFactory ossClientFactory) |
||||
|
{ |
||||
|
CurrentTenant = currentTenant; |
||||
|
OssClientFactory = ossClientFactory; |
||||
|
} |
||||
|
public virtual async Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
|
||||
|
var path = GetBasePath(request.Path); |
||||
|
var aliyunRequest = new DeleteObjectsRequest(request.Bucket, request.Objects.Select(x => x += path).ToList()); |
||||
|
|
||||
|
ossClient.DeleteObjects(aliyunRequest); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<OssContainer> CreateAsync(string name) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
|
||||
|
if (BucketExists(ossClient, name)) |
||||
|
{ |
||||
|
throw new BusinessException(code: OssManagementErrorCodes.ContainerAlreadyExists); |
||||
|
} |
||||
|
|
||||
|
var bucket = ossClient.CreateBucket(name); |
||||
|
|
||||
|
return new OssContainer( |
||||
|
bucket.Name, |
||||
|
bucket.CreationDate, |
||||
|
0L, |
||||
|
bucket.CreationDate, |
||||
|
new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "Id", bucket.Owner?.Id }, |
||||
|
{ "DisplayName", bucket.Owner?.DisplayName } |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<OssObject> CreateObjectAsync(CreateOssObjectRequest request) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
|
||||
|
var objectPath = GetBasePath(request.Path); |
||||
|
|
||||
|
var objectName = objectPath.IsNullOrWhiteSpace() |
||||
|
? request.Object |
||||
|
: objectPath + request.Object; |
||||
|
|
||||
|
if (ObjectExists(ossClient, request.Bucket, objectName)) |
||||
|
{ |
||||
|
throw new BusinessException(code: OssManagementErrorCodes.ObjectAlreadyExists); |
||||
|
} |
||||
|
|
||||
|
// 当一个对象名称是以 / 结尾时,不论该对象是否存有数据,都以目录的形式存在
|
||||
|
// 详情见:https://help.aliyun.com/document_detail/31910.html
|
||||
|
if (objectName.EndsWith("/") && |
||||
|
request.Content.IsNullOrEmpty()) |
||||
|
{ |
||||
|
var emptyStream = new MemoryStream(); |
||||
|
var emptyData = System.Text.Encoding.UTF8.GetBytes(""); |
||||
|
await emptyStream.WriteAsync(emptyData, 0, emptyData.Length); |
||||
|
request.SetContent(emptyStream); |
||||
|
} |
||||
|
|
||||
|
// 没有bucket则创建
|
||||
|
if (!BucketExists(ossClient, request.Bucket)) |
||||
|
{ |
||||
|
ossClient.CreateBucket(request.Bucket); |
||||
|
} |
||||
|
|
||||
|
var aliyunObjectRequest = new PutObjectRequest(request.Bucket, objectName, request.Content) |
||||
|
{ |
||||
|
Metadata = new ObjectMetadata() |
||||
|
}; |
||||
|
if (request.ExpirationTime.HasValue) |
||||
|
{ |
||||
|
aliyunObjectRequest.Metadata.ExpirationTime = DateTime.Now.Add(request.ExpirationTime.Value); |
||||
|
} |
||||
|
|
||||
|
var aliyunObject = ossClient.PutObject(aliyunObjectRequest); |
||||
|
|
||||
|
var ossObject = new OssObject( |
||||
|
!objectPath.IsNullOrWhiteSpace() |
||||
|
? objectName.Replace(objectPath, "") |
||||
|
: objectName, |
||||
|
objectPath, |
||||
|
DateTime.Now, |
||||
|
aliyunObject.ContentLength, |
||||
|
DateTime.Now, |
||||
|
aliyunObject.ResponseMetadata, |
||||
|
objectName.EndsWith("/") // 名称结尾是 / 符号的则为目录:https://help.aliyun.com/document_detail/31910.html
|
||||
|
) |
||||
|
{ |
||||
|
FullName = objectName |
||||
|
}; |
||||
|
|
||||
|
if (!Equals(request.Content, Stream.Null)) |
||||
|
{ |
||||
|
request.Content.Seek(0, SeekOrigin.Begin); |
||||
|
ossObject.SetContent(request.Content); |
||||
|
} |
||||
|
|
||||
|
return ossObject; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task DeleteAsync(string name) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
|
||||
|
if (BucketExists(ossClient, name)) |
||||
|
{ |
||||
|
ossClient.DeleteBucket(name); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task DeleteObjectAsync(GetOssObjectRequest request) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
|
||||
|
var objectPath = GetBasePath(request.Path); |
||||
|
|
||||
|
var objectName = objectPath.IsNullOrWhiteSpace() |
||||
|
? request.Object |
||||
|
: objectPath + request.Object; |
||||
|
|
||||
|
if (BucketExists(ossClient, request.Bucket) && |
||||
|
ObjectExists(ossClient, request.Bucket, objectName)) |
||||
|
{ |
||||
|
var objectListing = ossClient.ListObjects(request.Bucket, objectName); |
||||
|
if (objectListing.CommonPrefixes.Any() || |
||||
|
objectListing.ObjectSummaries.Any()) |
||||
|
{ |
||||
|
throw new BusinessException(code: OssManagementErrorCodes.ObjectDeleteWithNotEmpty); |
||||
|
// throw new ObjectDeleteWithNotEmptyException("00201", $"Can't not delete oss object {request.Object}, because it is not empty!");
|
||||
|
} |
||||
|
ossClient.DeleteObject(request.Bucket, objectName); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<bool> ExistsAsync(string name) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
|
||||
|
return BucketExists(ossClient, name); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<OssContainer> GetAsync(string name) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
if (!BucketExists(ossClient, name)) |
||||
|
{ |
||||
|
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); |
||||
|
// throw new ContainerNotFoundException($"Can't not found container {name} in aliyun blob storing");
|
||||
|
} |
||||
|
var bucket = ossClient.GetBucketInfo(name); |
||||
|
|
||||
|
return new OssContainer( |
||||
|
bucket.Bucket.Name, |
||||
|
bucket.Bucket.CreationDate, |
||||
|
0L, |
||||
|
bucket.Bucket.CreationDate, |
||||
|
new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "Id", bucket.Bucket.Owner?.Id }, |
||||
|
{ "DisplayName", bucket.Bucket.Owner?.DisplayName } |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<OssObject> GetObjectAsync(GetOssObjectRequest request) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
if (!BucketExists(ossClient, request.Bucket)) |
||||
|
{ |
||||
|
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound); |
||||
|
// throw new ContainerNotFoundException($"Can't not found container {request.Bucket} in aliyun blob storing");
|
||||
|
} |
||||
|
|
||||
|
var objectPath = GetBasePath(request.Path); |
||||
|
var objectName = objectPath.IsNullOrWhiteSpace() |
||||
|
? request.Object |
||||
|
: objectPath + request.Object; |
||||
|
|
||||
|
if (!ObjectExists(ossClient, request.Bucket, objectName)) |
||||
|
{ |
||||
|
throw new BusinessException(code: OssManagementErrorCodes.ObjectNotFound); |
||||
|
// throw new ContainerNotFoundException($"Can't not found object {objectName} in container {request.Bucket} with aliyun blob storing");
|
||||
|
} |
||||
|
|
||||
|
var aliyunOssObjectRequest = new GetObjectRequest(request.Bucket, objectName, request.Process); |
||||
|
var aliyunOssObject = ossClient.GetObject(aliyunOssObjectRequest); |
||||
|
var ossObject = new OssObject( |
||||
|
!objectPath.IsNullOrWhiteSpace() |
||||
|
? aliyunOssObject.Key.Replace(objectPath, "") |
||||
|
: aliyunOssObject.Key, |
||||
|
request.Path, |
||||
|
aliyunOssObject.Metadata.LastModified, |
||||
|
aliyunOssObject.Metadata.ContentLength, |
||||
|
aliyunOssObject.Metadata.LastModified, |
||||
|
aliyunOssObject.Metadata.UserMetadata, |
||||
|
aliyunOssObject.Key.EndsWith("/")) |
||||
|
{ |
||||
|
FullName = aliyunOssObject.Key |
||||
|
}; |
||||
|
|
||||
|
if (aliyunOssObject.IsSetResponseStream()) |
||||
|
{ |
||||
|
var memoryStream = new MemoryStream(); |
||||
|
await aliyunOssObject.Content.CopyToAsync(memoryStream); |
||||
|
memoryStream.Seek(0, SeekOrigin.Begin); |
||||
|
ossObject.SetContent(memoryStream); |
||||
|
} |
||||
|
|
||||
|
return ossObject; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<GetOssContainersResponse> GetListAsync(GetOssContainersRequest request) |
||||
|
{ |
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
|
||||
|
var aliyunRequest = new ListBucketsRequest |
||||
|
{ |
||||
|
Marker = request.Marker, |
||||
|
Prefix = request.Prefix, |
||||
|
MaxKeys = request.MaxKeys |
||||
|
}; |
||||
|
var bucketsResponse = ossClient.ListBuckets(aliyunRequest); |
||||
|
|
||||
|
return new GetOssContainersResponse( |
||||
|
bucketsResponse.Prefix, |
||||
|
bucketsResponse.Marker, |
||||
|
bucketsResponse.NextMaker, |
||||
|
bucketsResponse.MaxKeys ?? 0, |
||||
|
bucketsResponse.Buckets |
||||
|
.Select(x => new OssContainer( |
||||
|
x.Name, |
||||
|
x.CreationDate, |
||||
|
0L, |
||||
|
x.CreationDate, |
||||
|
new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "Id", x.Owner?.Id }, |
||||
|
{ "DisplayName", x.Owner?.DisplayName } |
||||
|
})) |
||||
|
.ToList()); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<GetOssObjectsResponse> GetObjectsAsync(GetOssObjectsRequest request) |
||||
|
{ |
||||
|
|
||||
|
var ossClient = await CreateClientAsync(); |
||||
|
|
||||
|
var objectPath = GetBasePath(request.Prefix); |
||||
|
var marker = !objectPath.IsNullOrWhiteSpace() && !request.Marker.IsNullOrWhiteSpace() |
||||
|
? request.Marker.Replace(objectPath, "") |
||||
|
: request.Marker; |
||||
|
var aliyunRequest = new ListObjectsRequest(request.BucketName) |
||||
|
{ |
||||
|
Marker = !marker.IsNullOrWhiteSpace() ? objectPath + marker : marker, |
||||
|
Prefix = objectPath, |
||||
|
MaxKeys = request.MaxKeys, |
||||
|
EncodingType = request.EncodingType, |
||||
|
Delimiter = request.Delimiter |
||||
|
}; |
||||
|
var objectsResponse = ossClient.ListObjects(aliyunRequest); |
||||
|
|
||||
|
var ossObjects = objectsResponse.ObjectSummaries |
||||
|
.Where(x => !x.Key.Equals(objectsResponse.Prefix))// 过滤当前的目录返回值
|
||||
|
.Select(x => new OssObject( |
||||
|
!objectPath.IsNullOrWhiteSpace() && !x.Key.Equals(objectPath) |
||||
|
? x.Key.Replace(objectPath, "") |
||||
|
: x.Key, // 去除目录名称
|
||||
|
request.Prefix, |
||||
|
x.LastModified, |
||||
|
x.Size, |
||||
|
x.LastModified, |
||||
|
new Dictionary<string, string> |
||||
|
{ |
||||
|
{ "Id", x.Owner?.Id }, |
||||
|
{ "DisplayName", x.Owner?.DisplayName } |
||||
|
}, |
||||
|
x.Key.EndsWith("/")) |
||||
|
{ |
||||
|
FullName = x.Key |
||||
|
}) |
||||
|
.ToList(); |
||||
|
// 当 Delimiter 为 / 时, objectsResponse.CommonPrefixes 可用于代表层级目录
|
||||
|
if (objectsResponse.CommonPrefixes.Any()) |
||||
|
{ |
||||
|
ossObjects.InsertRange(0, |
||||
|
objectsResponse.CommonPrefixes |
||||
|
.Select(x => new OssObject( |
||||
|
x.Replace(objectPath, ""), |
||||
|
request.Prefix, |
||||
|
null, |
||||
|
0L, |
||||
|
null, |
||||
|
null, |
||||
|
true))); |
||||
|
} |
||||
|
// 排序
|
||||
|
// TODO: 是否需要客户端来排序
|
||||
|
ossObjects.Sort(new OssObjectComparer()); |
||||
|
|
||||
|
return new GetOssObjectsResponse( |
||||
|
objectsResponse.BucketName, |
||||
|
request.Prefix, |
||||
|
marker, |
||||
|
!objectPath.IsNullOrWhiteSpace() && !objectsResponse.NextMarker.IsNullOrWhiteSpace() |
||||
|
? objectsResponse.NextMarker.Replace(objectPath, "") |
||||
|
: objectsResponse.NextMarker, |
||||
|
objectsResponse.Delimiter, |
||||
|
objectsResponse.MaxKeys, |
||||
|
ossObjects); |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetBasePath(string path) |
||||
|
{ |
||||
|
string objectPath = ""; |
||||
|
if (CurrentTenant.Id == null) |
||||
|
{ |
||||
|
objectPath += "host/"; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
objectPath += "tenants/" + CurrentTenant.Id.Value.ToString("D"); |
||||
|
} |
||||
|
|
||||
|
objectPath += path ?? ""; |
||||
|
|
||||
|
return objectPath.EnsureEndsWith('/'); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool BucketExists(IOss client, string bucketName) |
||||
|
{ |
||||
|
return client.DoesBucketExist(bucketName); |
||||
|
} |
||||
|
|
||||
|
protected virtual bool ObjectExists(IOss client, string bucketName, string objectName) |
||||
|
{ |
||||
|
return client.DoesObjectExist(bucketName, objectName); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<IOss> CreateClientAsync() |
||||
|
{ |
||||
|
return await OssClientFactory.CreateAsync<AbpOssManagementContainer>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using LINGYUN.Abp.BlobStoring.Aliyun; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement.Aliyun |
||||
|
{ |
||||
|
public class AliyunOssContainerFactory : IOssContainerFactory |
||||
|
{ |
||||
|
protected ICurrentTenant CurrentTenant { get; } |
||||
|
protected IOssClientFactory OssClientFactory { get; } |
||||
|
|
||||
|
public AliyunOssContainerFactory( |
||||
|
ICurrentTenant currentTenant, |
||||
|
IOssClientFactory ossClientFactory) |
||||
|
{ |
||||
|
CurrentTenant = currentTenant; |
||||
|
OssClientFactory = ossClientFactory; |
||||
|
} |
||||
|
|
||||
|
public IOssContainer Create() |
||||
|
{ |
||||
|
return new AliyunOssContainer( |
||||
|
CurrentTenant, |
||||
|
OssClientFactory); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
# LINGYUN.Abp.OssManagement.Aliyun |
||||
|
|
||||
|
阿里云oss容器接口 |
||||
|
|
||||
|
## 配置使用 |
||||
|
|
||||
|
模块按需引用 |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpOssManagementAliyunModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
// other |
||||
|
} |
||||
|
``` |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.Application; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpOssManagementDomainSharedModule), |
||||
|
typeof(AbpDddApplicationModule))] |
||||
|
public class AbpOssManagementApplicationContractsModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class BulkDeleteOssObjectInput |
||||
|
{ |
||||
|
[Required] |
||||
|
public string Bucket { get; set; } |
||||
|
|
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
public string[] Objects { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using System.IO; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class CreateOssObjectInput |
||||
|
{ |
||||
|
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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,73 @@ |
|||||
|
using LINGYUN.Abp.OssManagement.Localization; |
||||
|
using Volo.Abp.Features; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Validation.StringValues; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement.Features |
||||
|
{ |
||||
|
public class AbpOssManagementFeatureDefinitionProvider : FeatureDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(IFeatureDefinitionContext context) |
||||
|
{ |
||||
|
var featureGroup = context.AddGroup( |
||||
|
name: AbpOssManagementFeatureNames.GroupName, |
||||
|
displayName: L("Features:OssManagement")); |
||||
|
|
||||
|
var ossFeature = featureGroup.AddFeature( |
||||
|
name: AbpOssManagementFeatureNames.OssObject.Default, |
||||
|
displayName: L("Features:DisplayName:OssObject"), |
||||
|
description: L("Features:Description:OssObject")); |
||||
|
|
||||
|
ossFeature.CreateChild( |
||||
|
name: AbpOssManagementFeatureNames.OssObject.DownloadFile, |
||||
|
defaultValue: false.ToString(), |
||||
|
displayName: L("Features:DisplayName:DownloadFile"), |
||||
|
description: L("Features:Description:DownloadFile"), |
||||
|
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
||||
|
ossFeature.CreateChild( |
||||
|
name: AbpOssManagementFeatureNames.OssObject.DownloadLimit, |
||||
|
defaultValue: "1000", |
||||
|
displayName: L("Features:DisplayName:DownloadLimit"), |
||||
|
description: L("Features:Description:DownloadLimit"), |
||||
|
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用
|
||||
|
ossFeature.CreateChild( |
||||
|
name: AbpOssManagementFeatureNames.OssObject.DownloadInterval, |
||||
|
defaultValue: "1", |
||||
|
displayName: L("Features:DisplayName:DownloadInterval"), |
||||
|
description: L("Features:Description:DownloadInterval"), |
||||
|
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月
|
||||
|
|
||||
|
ossFeature.CreateChild( |
||||
|
name: AbpOssManagementFeatureNames.OssObject.UploadFile, |
||||
|
defaultValue: true.ToString(), |
||||
|
displayName: L("Features:DisplayName:UploadFile"), |
||||
|
description: L("Features:Description:UploadFile"), |
||||
|
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
||||
|
ossFeature.CreateChild( |
||||
|
name: AbpOssManagementFeatureNames.OssObject.UploadLimit, |
||||
|
defaultValue: "1000", |
||||
|
displayName: L("Features:DisplayName:UploadLimit"), |
||||
|
description: L("Features:Description:UploadLimit"), |
||||
|
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用
|
||||
|
ossFeature.CreateChild( |
||||
|
name: AbpOssManagementFeatureNames.OssObject.UploadInterval, |
||||
|
defaultValue: "1", |
||||
|
displayName: L("Features:DisplayName:UploadInterval"), |
||||
|
description: L("Features:Description:UploadInterval"), |
||||
|
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月
|
||||
|
|
||||
|
// TODO: 此功能需要控制器协同,暂时不实现
|
||||
|
//fileSystemFeature.CreateChild(
|
||||
|
// name: AbpOssManagementFeatureNames.OssObject.MaxUploadFileCount,
|
||||
|
// defaultValue: 1.ToString(),
|
||||
|
// displayName: L("Features:DisplayName:MaxUploadFileCount"),
|
||||
|
// description: L("Features:Description:MaxUploadFileCount"),
|
||||
|
// valueType: new FreeTextStringValueType(new NumericValueValidator(1, 10)));
|
||||
|
} |
||||
|
|
||||
|
protected ILocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<AbpOssManagementResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
namespace LINGYUN.Abp.OssManagement.Features |
||||
|
{ |
||||
|
public class AbpOssManagementFeatureNames |
||||
|
{ |
||||
|
public const string GroupName = "AbpOssManagement"; |
||||
|
|
||||
|
|
||||
|
public class OssObject |
||||
|
{ |
||||
|
public const string Default = GroupName + ".OssObject"; |
||||
|
/// <summary>
|
||||
|
/// 下载文件功能
|
||||
|
/// </summary>
|
||||
|
public const string DownloadFile = Default + ".DownloadFile"; |
||||
|
/// <summary>
|
||||
|
/// 下载文件功能限制次数
|
||||
|
/// </summary>
|
||||
|
public const string DownloadLimit = Default + ".DownloadLimit"; |
||||
|
/// <summary>
|
||||
|
/// 下载文件功能限制次数周期
|
||||
|
/// </summary>
|
||||
|
public const string DownloadInterval = Default + ".DownloadInterval"; |
||||
|
/// <summary>
|
||||
|
/// 上传文件功能
|
||||
|
/// </summary>
|
||||
|
public const string UploadFile = Default + ".UploadFile"; |
||||
|
/// <summary>
|
||||
|
/// 上传文件功能限制次数
|
||||
|
/// </summary>
|
||||
|
public const string UploadLimit = Default + ".UploadLimit"; |
||||
|
/// <summary>
|
||||
|
/// 上传文件功能限制次数周期
|
||||
|
/// </summary>
|
||||
|
public const string UploadInterval = Default + ".UploadInterval"; |
||||
|
/// <summary>
|
||||
|
/// 最大上传文件
|
||||
|
/// </summary>
|
||||
|
public const string MaxUploadFileCount = Default + ".MaxUploadFileCount"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetOssContainersInput : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public string Prefix { get; set; } |
||||
|
public string Marker { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetOssObjectInput |
||||
|
{ |
||||
|
[Required] |
||||
|
public string Bucket { get; set; } |
||||
|
|
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
public string Object { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetOssObjectsInput : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public string Bucket { get; set; } |
||||
|
public string Prefix { get; set; } |
||||
|
public string Delimiter { get; set; } |
||||
|
public string Marker { get; set; } |
||||
|
public string EncodingType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,14 +1,16 @@ |
|||||
using System.ComponentModel.DataAnnotations; |
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
namespace LINGYUN.Abp.FileManagement |
namespace LINGYUN.Abp.OssManagement |
||||
{ |
{ |
||||
public class FileSystemGetDto |
public class GetStaticFileInput |
||||
{ |
{ |
||||
[StringLength(255)] |
|
||||
public string Path { get; set; } |
|
||||
|
|
||||
[Required] |
[Required] |
||||
[StringLength(255)] |
|
||||
public string Name { get; set; } |
public string Name { get; set; } |
||||
|
|
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
public string Bucket { get; set; } |
||||
|
|
||||
|
public string Process { get; set; } |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public interface IOssContainerAppService: IApplicationService |
||||
|
{ |
||||
|
Task<OssContainerDto> CreateAsync(string name); |
||||
|
|
||||
|
Task<OssContainerDto> GetAsync(string name); |
||||
|
|
||||
|
Task DeleteAsync(string name); |
||||
|
|
||||
|
Task<OssContainersResultDto> GetListAsync(GetOssContainersInput input); |
||||
|
|
||||
|
Task<OssObjectsResultDto> GetObjectListAsync(GetOssObjectsInput input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public interface IOssObjectAppService : IApplicationService |
||||
|
{ |
||||
|
Task<OssObjectDto> CreateAsync(CreateOssObjectInput input); |
||||
|
|
||||
|
Task<OssObjectDto> GetAsync(GetOssObjectInput input); |
||||
|
|
||||
|
Task DeleteAsync(GetOssObjectInput input); |
||||
|
|
||||
|
Task BulkDeleteAsync(BulkDeleteOssObjectInput input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public interface IStaticFilesAppService: IApplicationService |
||||
|
{ |
||||
|
Task<Stream> GetAsync(GetStaticFileInput input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class OssContainerDto |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
public long Size { get; set; } |
||||
|
public DateTime CreationDate { get; set; } |
||||
|
public DateTime? LastModifiedDate { get; set; } |
||||
|
public IDictionary<string, string> Metadata { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class OssContainersResultDto |
||||
|
{ |
||||
|
public string Prefix { get; set; } |
||||
|
public string Marker { get; set; } |
||||
|
public string NextMarker { get; set; } |
||||
|
public int MaxKeys { get; set; } |
||||
|
public List<OssContainerDto> Containers { get; set; } = new List<OssContainerDto>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public static class OssManagementRemoteServiceConsts |
||||
|
{ |
||||
|
public const string RemoteServiceName = "AbpOssManagement"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class OssObjectDto |
||||
|
{ |
||||
|
public bool IsFolder { get; set; } |
||||
|
public string Path { get; set; } |
||||
|
public string Name { get; set; } |
||||
|
public long Size { get; set; } |
||||
|
public DateTime? CreationDate { get; set; } |
||||
|
public DateTime? LastModifiedDate { get; set; } |
||||
|
public IDictionary<string, string> Metadata { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class OssObjectsResultDto |
||||
|
{ |
||||
|
public string Bucket { get; set; } |
||||
|
public string Prefix { get; set; } |
||||
|
public string Delimiter { get; set; } |
||||
|
public string Marker { get; set; } |
||||
|
public string NextMarker { get; set; } |
||||
|
public int MaxKeys { get; set; } |
||||
|
public List<OssObjectDto> Objects { get; set; } = new List<OssObjectDto>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using LINGYUN.Abp.OssManagement.Localization; |
||||
|
using Volo.Abp.Authorization.Permissions; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement.Permissions |
||||
|
{ |
||||
|
public class AbpOssManagementPermissionDefinitionProvider : PermissionDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(IPermissionDefinitionContext context) |
||||
|
{ |
||||
|
var ossManagement = context.AddGroup(AbpOssManagementPermissions.GroupName, L("Permission:OssManagement")); |
||||
|
|
||||
|
var container = ossManagement.AddPermission(AbpOssManagementPermissions.Container.Default, L("Permission:Container")); |
||||
|
container.AddChild(AbpOssManagementPermissions.Container.Create, L("Permission:Create")); |
||||
|
container.AddChild(AbpOssManagementPermissions.Container.Delete, L("Permission:Delete")); |
||||
|
|
||||
|
var ossobject = ossManagement.AddPermission(AbpOssManagementPermissions.OssObject.Default, L("Permission:OssObject")); |
||||
|
ossobject.AddChild(AbpOssManagementPermissions.OssObject.Create, L("Permission:Create")); |
||||
|
ossobject.AddChild(AbpOssManagementPermissions.OssObject.Delete, L("Permission:Delete")); |
||||
|
ossobject.AddChild(AbpOssManagementPermissions.OssObject.Download, L("Permission:Download")); |
||||
|
} |
||||
|
|
||||
|
private static LocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<AbpOssManagementResource>(name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
namespace LINGYUN.Abp.OssManagement.Permissions |
||||
|
{ |
||||
|
public class AbpOssManagementPermissions |
||||
|
{ |
||||
|
public const string GroupName = "AbpOssManagement"; |
||||
|
|
||||
|
public class Container |
||||
|
{ |
||||
|
public const string Default = GroupName + ".Container"; |
||||
|
|
||||
|
public const string Create = Default + ".Create"; |
||||
|
|
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
} |
||||
|
|
||||
|
public class OssObject |
||||
|
{ |
||||
|
public const string Default = GroupName + ".OssObject"; |
||||
|
|
||||
|
public const string Create = Default + ".Create"; |
||||
|
|
||||
|
public const string Delete = Default + ".Delete"; |
||||
|
|
||||
|
public const string Download = Default + ".Download"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AutoMapper" Version="4.2.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Application.Contracts\LINGYUN.Abp.OssManagement.Application.Contracts.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Domain\LINGYUN.Abp.OssManagement.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,23 @@ |
|||||
|
using Volo.Abp.AutoMapper; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAutoMapperModule), |
||||
|
typeof(AbpOssManagementDomainModule), |
||||
|
typeof(AbpOssManagementApplicationContractsModule))] |
||||
|
public class AbpOssManagementApplicationModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAutoMapperObjectMapper<AbpOssManagementApplicationModule>(); |
||||
|
|
||||
|
Configure<AbpAutoMapperOptions>(options => |
||||
|
{ |
||||
|
options.AddProfile<OssManagementApplicationAutoMapperProfile>(validate: true); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
using LINGYUN.Abp.OssManagement.Permissions; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[Authorize(AbpOssManagementPermissions.Container.Default)] |
||||
|
public class OssContainerAppService : OssManagementApplicationServiceBase, IOssContainerAppService |
||||
|
{ |
||||
|
protected IOssContainerFactory OssContainerFactory { get; } |
||||
|
|
||||
|
public OssContainerAppService( |
||||
|
IOssContainerFactory ossContainerFactory) |
||||
|
{ |
||||
|
OssContainerFactory = ossContainerFactory; |
||||
|
} |
||||
|
|
||||
|
[Authorize(AbpOssManagementPermissions.Container.Create)] |
||||
|
public virtual async Task<OssContainerDto> CreateAsync(string name) |
||||
|
{ |
||||
|
var oss = CreateOssContainer(); |
||||
|
var container = await oss.CreateAsync(name); |
||||
|
|
||||
|
return ObjectMapper.Map<OssContainer, OssContainerDto>(container); |
||||
|
} |
||||
|
|
||||
|
[Authorize(AbpOssManagementPermissions.Container.Delete)] |
||||
|
public virtual async Task DeleteAsync(string name) |
||||
|
{ |
||||
|
var oss = CreateOssContainer(); |
||||
|
|
||||
|
await oss.DeleteAsync(name); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<OssContainerDto> GetAsync(string name) |
||||
|
{ |
||||
|
var oss = CreateOssContainer(); |
||||
|
var container = await oss.GetAsync(name); |
||||
|
|
||||
|
return ObjectMapper.Map<OssContainer, OssContainerDto>(container); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<OssContainersResultDto> GetListAsync(GetOssContainersInput input) |
||||
|
{ |
||||
|
var oss = CreateOssContainer(); |
||||
|
|
||||
|
var containerResponse = await oss.GetListAsync( |
||||
|
input.Prefix, input.Marker, input.MaxResultCount); |
||||
|
|
||||
|
return ObjectMapper.Map<GetOssContainersResponse, OssContainersResultDto>(containerResponse); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<OssObjectsResultDto> GetObjectListAsync(GetOssObjectsInput input) |
||||
|
{ |
||||
|
var oss = CreateOssContainer(); |
||||
|
|
||||
|
var ossObjectResponse = await oss.GetObjectsAsync( |
||||
|
input.Bucket, input.Prefix, input.Marker, |
||||
|
input.Delimiter, input.EncodingType, |
||||
|
input.MaxResultCount); |
||||
|
|
||||
|
return ObjectMapper.Map<GetOssObjectsResponse, OssObjectsResultDto>(ossObjectResponse); |
||||
|
} |
||||
|
|
||||
|
protected virtual IOssContainer CreateOssContainer() |
||||
|
{ |
||||
|
return OssContainerFactory.Create(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using AutoMapper; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class OssManagementApplicationAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public OssManagementApplicationAutoMapperProfile() |
||||
|
{ |
||||
|
CreateMap<OssContainer, OssContainerDto>(); |
||||
|
CreateMap<OssObject, OssObjectDto>() |
||||
|
.ForMember(dto => dto.Path, map => map.MapFrom(src => src.Prefix)); |
||||
|
|
||||
|
CreateMap<GetOssContainersResponse, OssContainersResultDto>(); |
||||
|
CreateMap<GetOssObjectsResponse, OssObjectsResultDto>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using LINGYUN.Abp.OssManagement.Localization; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class OssManagementApplicationServiceBase : ApplicationService |
||||
|
{ |
||||
|
protected OssManagementApplicationServiceBase() |
||||
|
{ |
||||
|
LocalizationResource = typeof(AbpOssManagementResource); |
||||
|
ObjectMapperContext = typeof(AbpOssManagementApplicationModule); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,113 @@ |
|||||
|
using LINGYUN.Abp.Features.LimitValidation; |
||||
|
using LINGYUN.Abp.OssManagement.Features; |
||||
|
using LINGYUN.Abp.OssManagement.Permissions; |
||||
|
using LINGYUN.Abp.OssManagement.Settings; |
||||
|
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.Features; |
||||
|
using Volo.Abp.IO; |
||||
|
using Volo.Abp.Settings; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[Authorize(AbpOssManagementPermissions.OssObject.Default)] |
||||
|
public class OssObjectAppService : OssManagementApplicationServiceBase, IOssObjectAppService |
||||
|
{ |
||||
|
protected IOssContainerFactory OssContainerFactory { get; } |
||||
|
|
||||
|
public OssObjectAppService( |
||||
|
IOssContainerFactory ossContainerFactory) |
||||
|
{ |
||||
|
OssContainerFactory = ossContainerFactory; |
||||
|
} |
||||
|
|
||||
|
[Authorize(AbpOssManagementPermissions.OssObject.Create)] |
||||
|
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] |
||||
|
[RequiresLimitFeature( |
||||
|
AbpOssManagementFeatureNames.OssObject.UploadLimit, |
||||
|
AbpOssManagementFeatureNames.OssObject.UploadInterval, |
||||
|
LimitPolicy.Month)] |
||||
|
public virtual async Task<OssObjectDto> CreateAsync(CreateOssObjectInput input) |
||||
|
{ |
||||
|
if (!input.Content.IsNullOrEmpty()) |
||||
|
{ |
||||
|
// 检查文件大小
|
||||
|
var fileSizeLimited = await SettingProvider |
||||
|
.GetAsync( |
||||
|
AbpOssManagementSettingNames.FileLimitLength, |
||||
|
AbpOssManagementSettingNames.DefaultFileLimitLength); |
||||
|
if (fileSizeLimited * 1024 * 1024 < input.Content.Length) |
||||
|
{ |
||||
|
ThrowValidationException(L["UploadFileSizeBeyondLimit", fileSizeLimited], nameof(input.Content)); |
||||
|
} |
||||
|
|
||||
|
// 文件扩展名
|
||||
|
var fileExtensionName = FileHelper.GetExtension(input.Object); |
||||
|
var fileAllowExtension = await SettingProvider.GetOrNullAsync(AbpOssManagementSettingNames.AllowFileExtensions); |
||||
|
// 检查文件扩展名
|
||||
|
if (!fileAllowExtension.Split(',') |
||||
|
.Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) |
||||
|
{ |
||||
|
ThrowValidationException(L["NotAllowedFileExtensionName", fileExtensionName], "FileName"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var oss = CreateOssContainer(); |
||||
|
|
||||
|
var createOssObjectRequest = new CreateOssObjectRequest( |
||||
|
input.Bucket, |
||||
|
input.Object, |
||||
|
input.Content, |
||||
|
input.Path, |
||||
|
input.ExpirationTime); |
||||
|
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); |
||||
|
|
||||
|
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); |
||||
|
} |
||||
|
|
||||
|
[Authorize(AbpOssManagementPermissions.OssObject.Delete)] |
||||
|
public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input) |
||||
|
{ |
||||
|
var oss = CreateOssContainer(); |
||||
|
|
||||
|
await oss.BulkDeleteObjectsAsync(input.Bucket, input.Objects, input.Path); |
||||
|
} |
||||
|
|
||||
|
[Authorize(AbpOssManagementPermissions.OssObject.Delete)] |
||||
|
public virtual async Task DeleteAsync(GetOssObjectInput input) |
||||
|
{ |
||||
|
var oss = CreateOssContainer(); |
||||
|
|
||||
|
await oss.DeleteObjectAsync(input.Bucket, input.Object, input.Path); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<OssObjectDto> GetAsync(GetOssObjectInput input) |
||||
|
{ |
||||
|
var oss = CreateOssContainer(); |
||||
|
|
||||
|
var ossObject = await oss.GetObjectAsync(input.Bucket, input.Object, input.Path); |
||||
|
|
||||
|
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); |
||||
|
} |
||||
|
|
||||
|
protected virtual IOssContainer CreateOssContainer() |
||||
|
{ |
||||
|
return OssContainerFactory.Create(); |
||||
|
} |
||||
|
|
||||
|
private static void ThrowValidationException(string message, string memberName) |
||||
|
{ |
||||
|
throw new AbpValidationException(message, |
||||
|
new List<ValidationResult> |
||||
|
{ |
||||
|
new ValidationResult(message, new[] {memberName}) |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using LINGYUN.Abp.Features.LimitValidation; |
||||
|
using LINGYUN.Abp.OssManagement.Features; |
||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Web; |
||||
|
using Volo.Abp.Features; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class StaticFilesAppService : OssManagementApplicationServiceBase, IStaticFilesAppService |
||||
|
{ |
||||
|
protected IOssContainerFactory OssContainerFactory { get; } |
||||
|
|
||||
|
public StaticFilesAppService( |
||||
|
IOssContainerFactory ossContainerFactory) |
||||
|
{ |
||||
|
OssContainerFactory = ossContainerFactory; |
||||
|
} |
||||
|
|
||||
|
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)] |
||||
|
[RequiresLimitFeature( |
||||
|
AbpOssManagementFeatureNames.OssObject.DownloadLimit, |
||||
|
AbpOssManagementFeatureNames.OssObject.DownloadInterval, |
||||
|
LimitPolicy.Month)] |
||||
|
public virtual async Task<Stream> GetAsync(GetStaticFileInput input) |
||||
|
{ |
||||
|
var ossObjectRequest = new GetOssObjectRequest( |
||||
|
HttpUtility.UrlDecode(input.Bucket), // 需要处理特殊字符
|
||||
|
HttpUtility.UrlDecode(input.Name), |
||||
|
HttpUtility.UrlDecode(input.Path), |
||||
|
HttpUtility.UrlDecode(input.Process)); |
||||
|
|
||||
|
var ossContainer = OssContainerFactory.Create(); |
||||
|
var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest); |
||||
|
|
||||
|
return ossObject.Content; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using LINGYUN.Abp.OssManagement.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Localization.ExceptionHandling; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Validation; |
||||
|
using Volo.Abp.Validation.Localization; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpValidationModule))] |
||||
|
public class AbpOssManagementDomainSharedModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpOssManagementDomainSharedModule>(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<AbpOssManagementResource>("en") |
||||
|
.AddBaseTypes( |
||||
|
typeof(AbpValidationResource) |
||||
|
).AddVirtualJson("/LINGYUN/Abp/OssManagement/Localization/Resources"); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpExceptionLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.MapCodeNamespace(OssManagementErrorCodes.Namespace, typeof(AbpOssManagementResource)); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("AbpOssManagement")] |
||||
|
public class AbpOssManagementResource |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"Abp.FileManagement:010001": "Cannot delete a container that has more than one object!", |
||||
|
"Abp.FileManagement:010402": "The container name already exists!", |
||||
|
"Abp.FileManagement:010404": "The queried container could not be found!", |
||||
|
"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:OssManagement": "Object Storage", |
||||
|
"Permission:Container": "Containers", |
||||
|
"Permission:OssObject": "Objects", |
||||
|
"Permission:Create": "Create", |
||||
|
"Permission:Delete": "Delete", |
||||
|
"Permission:Upload": "Upload", |
||||
|
"Permission:Download": "Download", |
||||
|
"FileNotFound": "The specified file does not exist!", |
||||
|
"PathNotFound": "The specified directory does not exist!", |
||||
|
"FilePathNotFound": "The file or directory does not exist!", |
||||
|
"PathAlreadyExists": "The specified directory already exists!", |
||||
|
"PathCannotBeDeletedWithNotEmpty": "The specified directory is not empty and cannot be deleted!", |
||||
|
"FilePathAlreadyExists": "The same file or directory already exists in the specified path!", |
||||
|
"UploadFileSizeBeyondLimit": "Upload file size cannot exceed {0} MB!", |
||||
|
"NotAllowedFileExtensionName": "Not allowed file extension: {0}!", |
||||
|
"DisplayName:OssManagement": "Object Storage", |
||||
|
"Description:OssManagement": "Object Storage", |
||||
|
"DisplayName:OssObject": "Objects", |
||||
|
"Description:OssObject": "Objects", |
||||
|
"DisplayName:FileLimitLength": "File limit size", |
||||
|
"Description:FileLimitLength": "Limit size of uploaded file in MB", |
||||
|
"DisplayName:AllowFileExtensions": "File extension", |
||||
|
"Description:AllowFileExtensions": "List of allowed extensions to upload files, with multiple extensions separated by, don't need a notation", |
||||
|
"Features:FileManagement": "File management", |
||||
|
"Features:DisplayName:FileSystem": "File system", |
||||
|
"Features:DisplayName:DownloadFile": "Download file", |
||||
|
"Features:Description:DownloadFile": "Whether to allow users to download files", |
||||
|
"Features:DisplayName:DownloadLimit": "Limit Of Downloads", |
||||
|
"Features:Description:DownloadLimit": "Limits the total number of times a file is downloaded within a specified period", |
||||
|
"Features:DisplayName:DownloadInterval": "Limit Downloads Interval", |
||||
|
"Features:Description:DownloadInterval": "The update period that limits the number of files downloaded. The time scale is: month. Default: 1", |
||||
|
"Features:DisplayName:UploadFile": "Upload file", |
||||
|
"Features:Description:UploadFile": "Whether to allow users to upload files", |
||||
|
"Features:DisplayName:UploadLimit": "Limit Of Uploads", |
||||
|
"Features:Description:UploadLimit": "Limits the total number of file uploads within a specified period", |
||||
|
"Features:DisplayName:UploadInterval": "Limit Uploads Interval", |
||||
|
"Features:Description:UploadInterval": "The update period that limits the number of files uploaded. The time scale is: month. Default: 1", |
||||
|
"Features:DisplayName:MaxUploadFileCount": "Maximum number of upload files", |
||||
|
"Features:Description:MaxUploadFileCount": "Limit the number of files a user uploads at a time" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"Abp.FileManagement:010001": "不能删除存在多个对象的容器!", |
||||
|
"Abp.FileManagement:010402": "容器名称已经存在!", |
||||
|
"Abp.FileManagement:010404": "未能找到查询的容器!", |
||||
|
"Abp.FileManagement:020001": "不能删除存在多个子级的对象!", |
||||
|
"Abp.FileManagement:020402": "对象名称已经存在!", |
||||
|
"Abp.FileManagement:020404": "未能找到查询的对象!", |
||||
|
"Abp.FileManagement:000405": "此路径对象名称已超出允许的最大长度,无法继续创建新对象!", |
||||
|
"Permission:OssManagement": "对象存储", |
||||
|
"Permission:Container": "容器管理", |
||||
|
"Permission:OssObject": "对象管理", |
||||
|
"Permission:Create": "新增", |
||||
|
"Permission:Delete": "删除", |
||||
|
"Permission:Upload": "上传", |
||||
|
"Permission:Download": "下载", |
||||
|
"FileNotFound": "指定的文件不存在!", |
||||
|
"PathNotFound": "指定的目录不存在!", |
||||
|
"FilePathNotFound": "文件或目录不存在!", |
||||
|
"PathAlreadyExists": "指定的目录已经存在!", |
||||
|
"PathCannotBeDeletedWithNotEmpty": "指定的目录不为空,不可删除此目录!", |
||||
|
"FilePathAlreadyExists": "指定的路径中已经有相同的文件或目录存在!", |
||||
|
"UploadFileSizeBeyondLimit": "上传文件大小不能超过 {0} MB!", |
||||
|
"NotAllowedFileExtensionName": "不被允许的文件扩展名: {0}!", |
||||
|
"DisplayName:OssManagement": "对象存储", |
||||
|
"Description:OssManagement": "对象存储", |
||||
|
"DisplayName:OssObject": "Oss对象", |
||||
|
"Description:OssObject": "Oss对象", |
||||
|
"DisplayName:FileLimitLength": "文件限制大小", |
||||
|
"Description:FileLimitLength": "上传文件的限制大小,单位(MB)", |
||||
|
"DisplayName:AllowFileExtensions": "文件扩展名", |
||||
|
"Description:AllowFileExtensions": "允许的上传文件扩展名列表,多个扩展名以,分隔,无需输入.符号", |
||||
|
"Features:OssManagement": "对象存储", |
||||
|
"Features:DisplayName:OssObject": "Oss管理", |
||||
|
"Features:DisplayName:DownloadFile": "下载文件", |
||||
|
"Features:Description:DownloadFile": "是否允许用户下载文件", |
||||
|
"Features:DisplayName:DownloadLimit": "限制下载文件次数", |
||||
|
"Features:Description:DownloadLimit": "在指定的周期内限制下载文件的总次数", |
||||
|
"Features:DisplayName:DownloadInterval": "限制下载文件周期", |
||||
|
"Features:Description:DownloadInterval": "限制下载文件次数的更新周期,时间刻度为:月,默认:1", |
||||
|
"Features:DisplayName:UploadFile": "上传文件", |
||||
|
"Features:Description:UploadFile": "是否允许用户上传文件", |
||||
|
"Features:DisplayName:UploadLimit": "限制上传文件次数", |
||||
|
"Features:Description:UploadLimit": "在指定的周期内限制上传文件的总次数", |
||||
|
"Features:DisplayName:UploadInterval": "限制上传文件周期", |
||||
|
"Features:Description:UploadInterval": "限制上传文件次数的更新周期,时间刻度为:月,默认:1", |
||||
|
"Features:DisplayName:MaxUploadFileCount": "上传文件数量", |
||||
|
"Features:Description:MaxUploadFileCount": "用户单次上传文件的限制数量" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public static class OssManagementErrorCodes |
||||
|
{ |
||||
|
public const string Namespace = "Abp.OssManagement"; |
||||
|
|
||||
|
public const string ContainerDeleteWithNotEmpty = Namespace + ":010001"; |
||||
|
public const string ContainerAlreadyExists = Namespace + ":010402"; |
||||
|
public const string ContainerNotFound = Namespace + ":010404"; |
||||
|
|
||||
|
public const string ObjectDeleteWithNotEmpty = Namespace + ":020001"; |
||||
|
public const string ObjectAlreadyExists = Namespace + ":020402"; |
||||
|
public const string ObjectNotFound = Namespace + ":020404"; |
||||
|
|
||||
|
public const string OssNameHasTooLong = Namespace + ":000405"; |
||||
|
} |
||||
|
} |
||||
16
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Settings/AbpFileManagementSettingDefinitionProvider.cs → aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Settings/AbpOssManagementSettingDefinitionProvider.cs
16
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Settings/AbpFileManagementSettingDefinitionProvider.cs → aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Settings/AbpOssManagementSettingDefinitionProvider.cs
@ -1,8 +1,12 @@ |
|||||
namespace LINGYUN.Abp.FileManagement.Settings |
namespace LINGYUN.Abp.OssManagement.Settings |
||||
{ |
{ |
||||
public class AbpFileManagementSettingNames |
public class AbpOssManagementSettingNames |
||||
{ |
{ |
||||
public const string GroupName = "Abp.FileManagement"; |
public const string GroupName = "Abp.OssManagement"; |
||||
|
/// <summary>
|
||||
|
/// 下载分包大小
|
||||
|
/// </summary>
|
||||
|
public const string DownloadPackageSize = GroupName + ".DownloadPackageSize"; |
||||
/// <summary>
|
/// <summary>
|
||||
/// 文件限制长度
|
/// 文件限制长度
|
||||
/// </summary>
|
/// </summary>
|
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace System.IO |
||||
|
{ |
||||
|
public static class StreamExtensions |
||||
|
{ |
||||
|
public static bool IsNullOrEmpty( |
||||
|
this Stream stream) |
||||
|
{ |
||||
|
return stream == null || |
||||
|
Equals(stream, Stream.Null); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.BlobStoring" Version="4.2.1" /> |
||||
|
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="4.2.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\common\LINGYUN.Abp.Features.LimitValidation\LINGYUN.Abp.Features.LimitValidation.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Domain.Shared\LINGYUN.Abp.OssManagement.Domain.Shared.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.BlobStoring; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[BlobContainerName("abp-oss-management")] |
||||
|
public class AbpOssManagementContainer |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using LINGYUN.Abp.Features.LimitValidation; |
||||
|
using Volo.Abp.Domain; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpDddDomainModule), |
||||
|
typeof(AbpMultiTenancyModule), |
||||
|
typeof(AbpFeaturesLimitValidationModule), |
||||
|
typeof(AbpOssManagementDomainSharedModule) |
||||
|
)] |
||||
|
public class AbpOssManagementDomainModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class BulkDeleteObjectRequest |
||||
|
{ |
||||
|
public string Bucket { get; } |
||||
|
public string Path { get; } |
||||
|
public ICollection<string> Objects { get; } |
||||
|
|
||||
|
public BulkDeleteObjectRequest( |
||||
|
[NotNull] string bucket, |
||||
|
ICollection<string> objects, |
||||
|
string path = "") |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(bucket, nameof(bucket)); |
||||
|
Check.NotNullOrEmpty(objects, nameof(objects)); |
||||
|
|
||||
|
Bucket = bucket; |
||||
|
Objects = objects; |
||||
|
Path = path; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class CreateOssObjectRequest |
||||
|
{ |
||||
|
public string Bucket { get; } |
||||
|
public string Path { get; } |
||||
|
public string Object { get; } |
||||
|
public Stream Content { get; private set; } |
||||
|
public TimeSpan? ExpirationTime { get; } |
||||
|
public CreateOssObjectRequest( |
||||
|
[NotNull] string bucket, |
||||
|
[NotNull] string @object, |
||||
|
[CanBeNull] Stream content, |
||||
|
[CanBeNull] string path = null, |
||||
|
[CanBeNull] TimeSpan? expirationTime = null) |
||||
|
{ |
||||
|
Bucket = Check.NotNullOrWhiteSpace(bucket, nameof(bucket)); |
||||
|
Object = Check.NotNullOrWhiteSpace(@object, nameof(@object)); |
||||
|
|
||||
|
Path = path; |
||||
|
Content = content; |
||||
|
ExpirationTime = expirationTime; |
||||
|
} |
||||
|
|
||||
|
public void SetContent(Stream content) |
||||
|
{ |
||||
|
Content = content; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetOssContainersRequest |
||||
|
{ |
||||
|
public string Prefix { get; } |
||||
|
public string Marker { get; } |
||||
|
public int? MaxKeys { get; } |
||||
|
public GetOssContainersRequest( |
||||
|
string prefix = null, |
||||
|
string marker = null, |
||||
|
int? maxKeys = 10) |
||||
|
{ |
||||
|
Prefix = prefix; |
||||
|
Marker = marker; |
||||
|
MaxKeys = maxKeys; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetOssContainersResponse |
||||
|
{ |
||||
|
public string Prefix { get; } |
||||
|
public string Marker { get; } |
||||
|
public string NextMarker { get; } |
||||
|
public int MaxKeys { get; } |
||||
|
public List<OssContainer> Containers { get; } |
||||
|
|
||||
|
public GetOssContainersResponse( |
||||
|
string prefix, |
||||
|
string marker, |
||||
|
string nextMarker, |
||||
|
int maxKeys, |
||||
|
List<OssContainer> containers) |
||||
|
{ |
||||
|
Prefix = prefix; |
||||
|
Marker = marker; |
||||
|
NextMarker = nextMarker; |
||||
|
MaxKeys = maxKeys; |
||||
|
|
||||
|
Containers = containers; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetOssObjectRequest |
||||
|
{ |
||||
|
public string Bucket { get; } |
||||
|
public string Path { get; } |
||||
|
public string Object { get; } |
||||
|
/// <summary>
|
||||
|
/// 需要处理文件的参数
|
||||
|
/// </summary>
|
||||
|
public string Process { get; } |
||||
|
|
||||
|
public GetOssObjectRequest( |
||||
|
[NotNull] string bucket, |
||||
|
[NotNull] string @object, |
||||
|
[CanBeNull] string path = "", |
||||
|
[CanBeNull] string process = "") |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(bucket, nameof(bucket)); |
||||
|
Check.NotNullOrWhiteSpace(@object, nameof(@object)); |
||||
|
|
||||
|
Bucket = bucket; |
||||
|
Object = @object; |
||||
|
Path = path; |
||||
|
Process = process; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetOssObjectsRequest |
||||
|
{ |
||||
|
public string BucketName { get; } |
||||
|
public string Prefix { get; } |
||||
|
public string Delimiter { get; } |
||||
|
public string Marker { get; } |
||||
|
public string EncodingType { get; } |
||||
|
public int? MaxKeys { get; } |
||||
|
public GetOssObjectsRequest( |
||||
|
[NotNull] string bucketName, |
||||
|
string prefix = null, |
||||
|
string marker = null, |
||||
|
string delimiter = null, |
||||
|
string encodingType = null, |
||||
|
int maxKeys = 10) |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(bucketName, nameof(bucketName)); |
||||
|
|
||||
|
BucketName = bucketName; |
||||
|
Prefix = prefix; |
||||
|
Marker = marker; |
||||
|
Delimiter = delimiter; |
||||
|
EncodingType = encodingType; |
||||
|
MaxKeys = maxKeys; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class GetOssObjectsResponse |
||||
|
{ |
||||
|
public string Bucket { get; } |
||||
|
public string Prefix { get; } |
||||
|
public string Delimiter { get; } |
||||
|
public string Marker { get; } |
||||
|
public string NextMarker { get; } |
||||
|
public int MaxKeys { get; } |
||||
|
public List<OssObject> Objects { get; } |
||||
|
public GetOssObjectsResponse( |
||||
|
string bucket, |
||||
|
string prefix, |
||||
|
string marker, |
||||
|
string nextMarker, |
||||
|
string delimiter, |
||||
|
int maxKeys, |
||||
|
List<OssObject> ossObjects) |
||||
|
{ |
||||
|
Bucket = bucket; |
||||
|
Prefix = prefix; |
||||
|
Marker = marker; |
||||
|
NextMarker = nextMarker; |
||||
|
Delimiter = delimiter; |
||||
|
MaxKeys = maxKeys; |
||||
|
|
||||
|
Objects = ossObjects; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Oss容器
|
||||
|
/// </summary>
|
||||
|
public interface IOssContainer |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 创建容器
|
||||
|
/// </summary>
|
||||
|
/// <param name="name"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<OssContainer> CreateAsync(string name); |
||||
|
/// <summary>
|
||||
|
/// 创建Oss对象
|
||||
|
/// </summary>
|
||||
|
/// <param name="request"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<OssObject> CreateObjectAsync(CreateOssObjectRequest request); |
||||
|
/// <summary>
|
||||
|
/// 获取容器信息
|
||||
|
/// </summary>
|
||||
|
/// <param name="name"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<OssContainer> GetAsync(string name); |
||||
|
/// <summary>
|
||||
|
/// 获取Oss对象信息
|
||||
|
/// </summary>
|
||||
|
/// <param name="request"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<OssObject> GetObjectAsync(GetOssObjectRequest request); |
||||
|
/// <summary>
|
||||
|
/// 删除容器
|
||||
|
/// </summary>
|
||||
|
/// <param name="name"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task DeleteAsync(string name); |
||||
|
/// <summary>
|
||||
|
/// 删除Oss对象
|
||||
|
/// </summary>
|
||||
|
/// <param name="request"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task DeleteObjectAsync(GetOssObjectRequest request); |
||||
|
/// <summary>
|
||||
|
/// 批量删除Oss对象
|
||||
|
/// </summary>
|
||||
|
/// <param name="request"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request); |
||||
|
/// <summary>
|
||||
|
/// 容器是否存在
|
||||
|
/// </summary>
|
||||
|
/// <param name="name"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<bool> ExistsAsync(string name); |
||||
|
/// <summary>
|
||||
|
/// 获取容器列表
|
||||
|
/// </summary>
|
||||
|
/// <param name="request"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<GetOssContainersResponse> GetListAsync(GetOssContainersRequest request); |
||||
|
/// <summary>
|
||||
|
/// 获取对象列表
|
||||
|
/// </summary>
|
||||
|
/// <param name="request"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<GetOssObjectsResponse> GetObjectsAsync(GetOssObjectsRequest request); |
||||
|
// Task<List<OssObject>> GetObjectsAsync(string name, string prefix = null, string marker = null, string delimiter = null, int maxResultCount = 10);
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public static class IOssContainerExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 如果不存在容器则创建
|
||||
|
/// </summary>
|
||||
|
/// <param name="ossContainer"></param>
|
||||
|
/// <param name="name"></param>
|
||||
|
/// <returns>返回容器信息</returns>
|
||||
|
public static async Task<OssContainer> CreateIfNotExistsAsync( |
||||
|
this IOssContainer ossContainer, |
||||
|
string name) |
||||
|
{ |
||||
|
if (! await ossContainer.ExistsAsync(name)) |
||||
|
{ |
||||
|
await ossContainer.CreateAsync(name); |
||||
|
} |
||||
|
|
||||
|
return await ossContainer.GetAsync(name); |
||||
|
} |
||||
|
|
||||
|
public static async Task DeleteObjectAsync( |
||||
|
this IOssContainer ossContainer, |
||||
|
string bucket, |
||||
|
string @object, |
||||
|
string path = "") |
||||
|
{ |
||||
|
await ossContainer.DeleteObjectAsync( |
||||
|
new GetOssObjectRequest(bucket, @object, path)); |
||||
|
} |
||||
|
|
||||
|
public static async Task BulkDeleteObjectsAsync( |
||||
|
this IOssContainer ossContainer, |
||||
|
string bucketName, |
||||
|
ICollection<string> objectNames, |
||||
|
string path = "") |
||||
|
{ |
||||
|
await ossContainer.BulkDeleteObjectsAsync( |
||||
|
new BulkDeleteObjectRequest(bucketName, objectNames, path)); |
||||
|
} |
||||
|
|
||||
|
public static async Task<GetOssContainersResponse> GetListAsync( |
||||
|
this IOssContainer ossContainer, |
||||
|
string prefix = null, |
||||
|
string marker = null, |
||||
|
int maxResultCount = 10) |
||||
|
{ |
||||
|
return await ossContainer.GetListAsync( |
||||
|
new GetOssContainersRequest(prefix, marker, maxResultCount)); |
||||
|
} |
||||
|
|
||||
|
public static async Task<OssObject> GetObjectAsync( |
||||
|
this IOssContainer ossContainer, |
||||
|
string bucket, |
||||
|
string @object, |
||||
|
string path = "") |
||||
|
{ |
||||
|
return await ossContainer.GetObjectAsync( |
||||
|
new GetOssObjectRequest(bucket, @object, path)); |
||||
|
} |
||||
|
|
||||
|
public static async Task<GetOssObjectsResponse> GetObjectsAsync( |
||||
|
this IOssContainer ossContainer, |
||||
|
string name, |
||||
|
string prefix = null, |
||||
|
string marker = null, |
||||
|
string delimiter = null, |
||||
|
string encodingType = null, |
||||
|
int maxResultCount = 10) |
||||
|
{ |
||||
|
return await ossContainer.GetObjectsAsync( |
||||
|
new GetOssObjectsRequest(name, prefix, marker, delimiter, encodingType, maxResultCount)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Oss容器构建工厂
|
||||
|
/// </summary>
|
||||
|
public interface IOssContainerFactory |
||||
|
{ |
||||
|
IOssContainer Create(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Oss容器构建工厂
|
||||
|
/// </summary>
|
||||
|
public interface IOssContainerFactory<TConfiguration> |
||||
|
{ |
||||
|
IOssContainer Create(TConfiguration configuration); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 描述了一个容器的状态信息
|
||||
|
/// </summary>
|
||||
|
public class OssContainer |
||||
|
{ |
||||
|
public string Name { get; } |
||||
|
public long Size { get; } |
||||
|
public DateTime CreationDate { get; } |
||||
|
public DateTime? LastModifiedDate { get; } |
||||
|
public IDictionary<string, string> Metadata { get; } |
||||
|
|
||||
|
public OssContainer( |
||||
|
string name, |
||||
|
DateTime creationDate, |
||||
|
long size = 0, |
||||
|
DateTime? lastModifiedDate = null, |
||||
|
IDictionary<string, string> metadata = null) |
||||
|
{ |
||||
|
Name = name; |
||||
|
CreationDate = creationDate; |
||||
|
LastModifiedDate = lastModifiedDate; |
||||
|
Size = size; |
||||
|
Metadata = metadata ?? new Dictionary<string, string>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 描述了一个对象的状态信息
|
||||
|
/// </summary>
|
||||
|
public class OssObject |
||||
|
{ |
||||
|
private Stream _content; |
||||
|
|
||||
|
public bool IsFolder { get; } |
||||
|
public string Name { get; } |
||||
|
public string FullName { get; set; } |
||||
|
public string Prefix { get; } |
||||
|
public long Size { get; } |
||||
|
public Stream Content => _content; |
||||
|
public DateTime? CreationDate { get; } |
||||
|
public DateTime? LastModifiedDate { get; } |
||||
|
public IDictionary<string, string> Metadata { get; } |
||||
|
public OssObject( |
||||
|
string name, |
||||
|
string prefix, |
||||
|
DateTime? creationDate = null, |
||||
|
long size = 0, |
||||
|
DateTime? lastModifiedDate = null, |
||||
|
IDictionary<string, string> metadata = null, |
||||
|
bool isFolder = false) |
||||
|
{ |
||||
|
Name = name; |
||||
|
Prefix = prefix; |
||||
|
CreationDate = creationDate; |
||||
|
LastModifiedDate = lastModifiedDate; |
||||
|
Size = size; |
||||
|
IsFolder = isFolder; |
||||
|
Metadata = metadata ?? new Dictionary<string, string>(); |
||||
|
} |
||||
|
|
||||
|
public void SetContent(Stream stream) |
||||
|
{ |
||||
|
_content = stream; |
||||
|
if (!_content.IsNullOrEmpty()) |
||||
|
{ |
||||
|
_content.Seek(0, SeekOrigin.Begin); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.OssManagement |
||||
|
{ |
||||
|
public class OssObjectComparer : IComparer<OssObject> |
||||
|
{ |
||||
|
public virtual int Compare(OssObject x, OssObject y) |
||||
|
{ |
||||
|
if (x.IsFolder && y.IsFolder) |
||||
|
{ |
||||
|
return x.Name.CompareTo(y.Name); |
||||
|
} |
||||
|
|
||||
|
if (x.IsFolder && !y.IsFolder) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
if (!x.IsFolder && y.IsFolder) |
||||
|
{ |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
return x.Name.CompareTo(y.Name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue