Browse Source

Optimize the OSS management interface and interface

pull/216/head
cKey 5 years ago
parent
commit
0b525e74d4
  1. 23
      aspnet-core/LINGYUN.MicroService.All.sln
  2. 35
      aspnet-core/LINGYUN.MicroService.Platform.sln
  3. 2
      aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj
  4. 5
      aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IOssClientFactory.cs
  5. 12
      aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs
  6. 13
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/LINGYUN.Abp.FileManagement.Aliyun.csproj
  7. 17
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/LINGYUN/Abp/FileManagement/Aliyun/AbpFileManagementAliyunModule.cs
  8. 369
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/LINGYUN/Abp/FileManagement/Aliyun/AliyunOssContainer.cs
  9. 26
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/LINGYUN/Abp/FileManagement/Aliyun/AliyunOssContainerFactory.cs
  10. 15
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/README.md
  11. 15
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/BulkDeleteOssObjectInput.cs
  12. 19
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/CreateOssObjectInput.cs
  13. 10
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetOssContainersInput.cs
  14. 15
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetOssObjectInput.cs
  15. 13
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetOssObjectsInput.cs
  16. 16
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetStaticFileInput.cs
  17. 18
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IOssContainerAppService.cs
  18. 16
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IOssObjectAppService.cs
  19. 11
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IStaticFilesAppService.cs
  20. 14
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/OssContainerDto.cs
  21. 13
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/OssContainersResultDto.cs
  22. 16
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/OssObjectDto.cs
  23. 15
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/OssObjectsResultDto.cs
  24. 4
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN.Abp.FileManagement.Application.csproj
  25. 13
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/AbpFileManagementApplicationModule.cs
  26. 17
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/FileManagementApplicationAutoMapperProfile.cs
  27. 10
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/FileSystemAppService.cs
  28. 67
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/OssContainerAppService.cs
  29. 100
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/OssObjectAppService.cs
  30. 31
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/StaticFilesAppService.cs
  31. 6
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/AbpFileManagementDomainSharedModule.cs
  32. 19
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/FileManagementErrorCodes.cs
  33. 6
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/en.json
  34. 6
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/zh-Hans.json
  35. 4
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Settings/AbpFileManagementSettingNames.cs
  36. 12
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/System/IO/StreamExtensions.cs
  37. 3
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN.Abp.FileManagement.Domain.csproj
  38. 2
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/AbpFileManagementContainer.cs
  39. 26
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/BulkDeleteObjectRequest.cs
  40. 35
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/CreateOssObjectRequest.cs
  41. 18
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssContainersRequest.cs
  42. 28
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssContainersResponse.cs
  43. 31
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssObjectRequest.cs
  44. 32
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssObjectsRequest.cs
  45. 33
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssObjectsResponse.cs
  46. 72
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/IOssContainer.cs
  47. 79
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/IOssContainerExtensions.cs
  48. 18
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/IOssContainerFactory.cs
  49. 31
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/OssContainer.cs
  50. 50
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/OssObject.cs
  51. 27
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/OssObjectComparer.cs
  52. 16
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp.csproj
  53. 16
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp/LINGYUN/Abp/FileManagement/FileSystem/ImageSharp/AbpFileManagementFileSystemImageSharpModule.cs
  54. 118
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp/LINGYUN/Abp/FileManagement/FileSystem/ImageSharp/ImageSharpFileSystemOssObjectProcesser.cs
  55. 15
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp/README.md
  56. 17
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN.Abp.FileManagement.FileSystem.csproj
  57. 17
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/AbpFileManagementFileSystemModule.cs
  58. 512
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssContainer.cs
  59. 46
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssContainerFactory.cs
  60. 32
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssObjectContext.cs
  61. 19
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssOptions.cs
  62. 15
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssOptionsExtensions.cs
  63. 18
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssProviderArgs.cs
  64. 10
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/IFileSystemOssObjectProcesserContributor.cs
  65. 15
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/NoneFileSystemOssObjectProcesser.cs
  66. 15
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/README.md
  67. 56
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/OssContainerController.cs
  68. 81
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/OssObjectController.cs
  69. 87
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/StaticFilesController.cs
  70. 12
      aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/UploadOssObjectInput.cs
  71. BIN
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/event-bus-cap.db
  72. 34
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs
  73. 40
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/DomainTenantResolveContributor.cs
  74. 50
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/HeaderTenantResolveContributor.cs
  75. 3
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj
  76. 66
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/TenantConfigurationProvider.cs
  77. 48
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/TenantResolver.cs
  78. 129
      vueJs/src/api/oss-manager.ts
  79. 17
      vueJs/src/directives/el-table-lazy-load/index.ts
  80. 1
      vueJs/src/directives/index.ts
  81. 162
      vueJs/src/views/oss-management/components/OssObjectProfile.vue
  82. 476
      vueJs/src/views/oss-management/index.vue

23
aspnet-core/LINGYUN.MicroService.All.sln

@ -269,10 +269,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Tencent", "modu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Notifications.Sms", "modules\common\LINGYUN.Abp.Notifications.Sms\LINGYUN.Abp.Notifications.Sms.csproj", "{8C3312E7-F51E-4780-A893-CE0E0B80B579}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Aliyun.SettingManagement", "modules\cloud-aliyun\LINGYUN.Abp.Aliyun.SettingManagement\LINGYUN.Abp.Aliyun.SettingManagement.csproj", "{FE0F0889-C4AF-43C5-B851-B8CCC873BA2C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Aliyun.SettingManagement", "modules\cloud-aliyun\LINGYUN.Abp.Aliyun.SettingManagement\LINGYUN.Abp.Aliyun.SettingManagement.csproj", "{FE0F0889-C4AF-43C5-B851-B8CCC873BA2C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Aliyun.Tests", "tests\LINGYUN.Abp.Aliyun.Tests\LINGYUN.Abp.Aliyun.Tests.csproj", "{B86EBB6F-A27F-4277-8265-937951A9DCB0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.FileManagement.Aliyun", "modules\file-management\LINGYUN.Abp.FileManagement.Aliyun\LINGYUN.Abp.FileManagement.Aliyun.csproj", "{35B17218-9FB6-439E-AF73-9A1454BC923C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.FileManagement.FileSystem", "modules\file-management\LINGYUN.Abp.FileManagement.FileSystem\LINGYUN.Abp.FileManagement.FileSystem.csproj", "{D5036D3F-1C53-47EE-BA50-AD290AE062D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FileManagement.FileSystem.ImageSharp", "modules\file-management\LINGYUN.Abp.FileManagement.FileSystem.ImageSharp\LINGYUN.Abp.FileManagement.FileSystem.ImageSharp.csproj", "{3E5EBCEC-78C9-4A1A-BF04-A216AA6A921F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -719,6 +725,18 @@ Global
{B86EBB6F-A27F-4277-8265-937951A9DCB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B86EBB6F-A27F-4277-8265-937951A9DCB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B86EBB6F-A27F-4277-8265-937951A9DCB0}.Release|Any CPU.Build.0 = Release|Any CPU
{35B17218-9FB6-439E-AF73-9A1454BC923C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35B17218-9FB6-439E-AF73-9A1454BC923C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35B17218-9FB6-439E-AF73-9A1454BC923C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35B17218-9FB6-439E-AF73-9A1454BC923C}.Release|Any CPU.Build.0 = Release|Any CPU
{D5036D3F-1C53-47EE-BA50-AD290AE062D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5036D3F-1C53-47EE-BA50-AD290AE062D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5036D3F-1C53-47EE-BA50-AD290AE062D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5036D3F-1C53-47EE-BA50-AD290AE062D7}.Release|Any CPU.Build.0 = Release|Any CPU
{3E5EBCEC-78C9-4A1A-BF04-A216AA6A921F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E5EBCEC-78C9-4A1A-BF04-A216AA6A921F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E5EBCEC-78C9-4A1A-BF04-A216AA6A921F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E5EBCEC-78C9-4A1A-BF04-A216AA6A921F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -856,6 +874,9 @@ Global
{8C3312E7-F51E-4780-A893-CE0E0B80B579} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E}
{FE0F0889-C4AF-43C5-B851-B8CCC873BA2C} = {14CDBAD1-10C8-464A-B445-1F727C988010}
{B86EBB6F-A27F-4277-8265-937951A9DCB0} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F}
{35B17218-9FB6-439E-AF73-9A1454BC923C} = {B05CB08F-C088-4D6D-97EE-A94A5D1AE4A6}
{D5036D3F-1C53-47EE-BA50-AD290AE062D7} = {B05CB08F-C088-4D6D-97EE-A94A5D1AE4A6}
{3E5EBCEC-78C9-4A1A-BF04-A216AA6A921F} = {B05CB08F-C088-4D6D-97EE-A94A5D1AE4A6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718}

35
aspnet-core/LINGYUN.MicroService.Platform.sln

@ -45,9 +45,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TestsBase", "te
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.EntityFrameworkCore.Tests", "tests\LINGYUN.Abp.EntityFrameworkCore.Tests\LINGYUN.Abp.EntityFrameworkCore.Tests.csproj", "{B2C0271C-3FE6-4C45-B162-4DE00E542A55}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Platform.EntityFrameworkCore.Tests", "tests\LINGYUN.Platform.EntityFrameworkCore.Tests\LINGYUN.Platform.EntityFrameworkCore.Tests.csproj", "{263C49A9-34B9-449B-ABBC-D328210C023D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Platform.EntityFrameworkCore.Tests", "tests\LINGYUN.Platform.EntityFrameworkCore.Tests\LINGYUN.Platform.EntityFrameworkCore.Tests.csproj", "{263C49A9-34B9-449B-ABBC-D328210C023D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Platform.Domain.Tests", "tests\LINGYUN.Platform.Domain.Tests\LINGYUN.Platform.Domain.Tests.csproj", "{C60A06F2-0F4C-483F-BE2B-B103F0D726CE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Platform.Domain.Tests", "tests\LINGYUN.Platform.Domain.Tests\LINGYUN.Platform.Domain.Tests.csproj", "{C60A06F2-0F4C-483F-BE2B-B103F0D726CE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FileManagement.Aliyun", "modules\file-management\LINGYUN.Abp.FileManagement.Aliyun\LINGYUN.Abp.FileManagement.Aliyun.csproj", "{104EDC09-0CEA-4AB0-BFF5-B009D4679419}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{265D5E44-682B-49BC-984A-BDD8CA45E60E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Aliyun", "modules\cloud-aliyun\LINGYUN.Abp.Aliyun\LINGYUN.Abp.Aliyun.csproj", "{8A393F7F-85A2-48ED-9B56-9CEFF3BDE34A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.BlobStoring.Aliyun", "modules\common\LINGYUN.Abp.BlobStoring.Aliyun\LINGYUN.Abp.BlobStoring.Aliyun.csproj", "{95E0D070-ACFB-40DF-A4EC-FC75EA5AF6B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FileManagement.FileSystem", "modules\file-management\LINGYUN.Abp.FileManagement.FileSystem\LINGYUN.Abp.FileManagement.FileSystem.csproj", "{B5569DCD-445E-445B-87E7-D8D4E03F0F76}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -123,6 +133,22 @@ Global
{C60A06F2-0F4C-483F-BE2B-B103F0D726CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C60A06F2-0F4C-483F-BE2B-B103F0D726CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C60A06F2-0F4C-483F-BE2B-B103F0D726CE}.Release|Any CPU.Build.0 = Release|Any CPU
{104EDC09-0CEA-4AB0-BFF5-B009D4679419}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{104EDC09-0CEA-4AB0-BFF5-B009D4679419}.Debug|Any CPU.Build.0 = Debug|Any CPU
{104EDC09-0CEA-4AB0-BFF5-B009D4679419}.Release|Any CPU.ActiveCfg = Release|Any CPU
{104EDC09-0CEA-4AB0-BFF5-B009D4679419}.Release|Any CPU.Build.0 = Release|Any CPU
{8A393F7F-85A2-48ED-9B56-9CEFF3BDE34A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A393F7F-85A2-48ED-9B56-9CEFF3BDE34A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A393F7F-85A2-48ED-9B56-9CEFF3BDE34A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A393F7F-85A2-48ED-9B56-9CEFF3BDE34A}.Release|Any CPU.Build.0 = Release|Any CPU
{95E0D070-ACFB-40DF-A4EC-FC75EA5AF6B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95E0D070-ACFB-40DF-A4EC-FC75EA5AF6B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95E0D070-ACFB-40DF-A4EC-FC75EA5AF6B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95E0D070-ACFB-40DF-A4EC-FC75EA5AF6B0}.Release|Any CPU.Build.0 = Release|Any CPU
{B5569DCD-445E-445B-87E7-D8D4E03F0F76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5569DCD-445E-445B-87E7-D8D4E03F0F76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5569DCD-445E-445B-87E7-D8D4E03F0F76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5569DCD-445E-445B-87E7-D8D4E03F0F76}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -148,6 +174,11 @@ Global
{B2C0271C-3FE6-4C45-B162-4DE00E542A55} = {CCEFF583-4EEE-433F-8568-9E64166B41FE}
{263C49A9-34B9-449B-ABBC-D328210C023D} = {CCEFF583-4EEE-433F-8568-9E64166B41FE}
{C60A06F2-0F4C-483F-BE2B-B103F0D726CE} = {CCEFF583-4EEE-433F-8568-9E64166B41FE}
{104EDC09-0CEA-4AB0-BFF5-B009D4679419} = {C7D0EB39-3418-4A7C-AD94-FAB76F023E88}
{265D5E44-682B-49BC-984A-BDD8CA45E60E} = {15BDA03E-DE8E-46E4-96A8-CA3F2872E812}
{8A393F7F-85A2-48ED-9B56-9CEFF3BDE34A} = {265D5E44-682B-49BC-984A-BDD8CA45E60E}
{95E0D070-ACFB-40DF-A4EC-FC75EA5AF6B0} = {265D5E44-682B-49BC-984A-BDD8CA45E60E}
{B5569DCD-445E-445B-87E7-D8D4E03F0F76} = {C7D0EB39-3418-4A7C-AD94-FAB76F023E88}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {03D3B66F-8926-4C00-B7AB-A21761EC859E}

2
aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj

@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.10.0" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
<PackageReference Include="Volo.Abp.BlobStoring" Version="4.2.1" />
</ItemGroup>

5
aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IOssClientFactory.cs

@ -5,6 +5,11 @@ namespace LINGYUN.Abp.BlobStoring.Aliyun
{
public interface IOssClientFactory
{
/// <summary>
/// 构建Oss客户端
/// </summary>
/// <returns></returns>
Task<IOss> CreateAsync<TContainer>();
/// <summary>
/// 通过配置信息构建Oss客户端调用
/// </summary>

12
aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs

@ -1,5 +1,7 @@
using Aliyun.OSS;
using LINGYUN.Abp.Aliyun;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
@ -8,11 +10,21 @@ namespace LINGYUN.Abp.BlobStoring.Aliyun
{
public class OssClientFactory : AliyunClientFactory<IOss, AliyunBlobProviderConfiguration>, IOssClientFactory, ITransientDependency
{
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
public OssClientFactory(
ISettingProvider settingProvider,
IBlobContainerConfigurationProvider configurationProvider,
IDistributedCache<AliyunBasicSessionCredentialsCacheItem> cache)
: base(settingProvider, cache)
{
ConfigurationProvider = configurationProvider;
}
public virtual async Task<IOss> CreateAsync<TContainer>()
{
var configuration = ConfigurationProvider.Get<TContainer>();
return await CreateAsync(configuration.GetAliyunConfiguration());
}
/// <summary>
/// 普通方式构建Oss客户端

13
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/LINGYUN.Abp.FileManagement.Aliyun.csproj

@ -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.FileManagement.Domain\LINGYUN.Abp.FileManagement.Domain.csproj" />
</ItemGroup>
</Project>

17
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/LINGYUN/Abp/FileManagement/Aliyun/AbpFileManagementAliyunModule.cs

@ -0,0 +1,17 @@
using LINGYUN.Abp.BlobStoring.Aliyun;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.FileManagement.Aliyun
{
[DependsOn(
typeof(AbpBlobStoringAliyunModule),
typeof(AbpFileManagementDomainModule))]
public class AbpFileManagementAliyunModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTransient<IOssContainerFactory, AliyunOssContainerFactory>();
}
}
}

369
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/LINGYUN/Abp/FileManagement/Aliyun/AliyunOssContainer.cs

@ -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.FileManagement.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: FileManagementErrorCodes.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: FileManagementErrorCodes.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: FileManagementErrorCodes.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: FileManagementErrorCodes.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: FileManagementErrorCodes.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: FileManagementErrorCodes.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<AbpFileManagementContainer>();
}
}
}

26
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/LINGYUN/Abp/FileManagement/Aliyun/AliyunOssContainerFactory.cs

@ -0,0 +1,26 @@
using LINGYUN.Abp.BlobStoring.Aliyun;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.FileManagement.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);
}
}
}

15
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Aliyun/README.md

@ -0,0 +1,15 @@
# LINGYUN.Abp.FileManagement.Aliyun
阿里云oss容器接口
## 配置使用
模块按需引用
```csharp
[DependsOn(typeof(AbpFileManagementAliyunModule))]
public class YouProjectModule : AbpModule
{
// other
}
```

15
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/BulkDeleteOssObjectInput.cs

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace LINGYUN.Abp.FileManagement
{
public class BulkDeleteOssObjectInput
{
[Required]
public string Bucket { get; set; }
public string Path { get; set; }
[Required]
public string[] Objects { get; set; }
}
}

19
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/CreateOssObjectInput.cs

@ -0,0 +1,19 @@
using System;
using System.IO;
namespace LINGYUN.Abp.FileManagement
{
public class CreateOssObjectInput
{
public string Bucket { get; set; }
public string Path { get; set; }
public string Object { get; set; }
public Stream Content { get; set; }
public TimeSpan? ExpirationTime { get; set; }
public void SetContent(Stream content)
{
Content = content;
}
}
}

10
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetOssContainersInput.cs

@ -0,0 +1,10 @@
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.FileManagement
{
public class GetOssContainersInput : PagedAndSortedResultRequestDto
{
public string Prefix { get; set; }
public string Marker { get; set; }
}
}

15
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetOssObjectInput.cs

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace LINGYUN.Abp.FileManagement
{
public class GetOssObjectInput
{
[Required]
public string Bucket { get; set; }
public string Path { get; set; }
[Required]
public string Object { get; set; }
}
}

13
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetOssObjectsInput.cs

@ -0,0 +1,13 @@
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.FileManagement
{
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; }
}
}

16
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/GetStaticFileInput.cs

@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
namespace LINGYUN.Abp.FileManagement
{
public class GetStaticFileInput
{
[Required]
public string Name { get; set; }
public string Path { get; set; }
public string Bucket { get; set; }
public string Process { get; set; }
}
}

18
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IOssContainerAppService.cs

@ -0,0 +1,18 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.FileManagement
{
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);
}
}

16
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IOssObjectAppService.cs

@ -0,0 +1,16 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.FileManagement
{
public interface IOssObjectAppService : IApplicationService
{
Task<OssObjectDto> CreateAsync(CreateOssObjectInput input);
Task<OssObjectDto> GetAsync(GetOssObjectInput input);
Task DeleteAsync(GetOssObjectInput input);
Task BulkDeleteAsync(BulkDeleteOssObjectInput input);
}
}

11
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/IStaticFilesAppService.cs

@ -0,0 +1,11 @@
using System.IO;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.FileManagement
{
public interface IStaticFilesAppService: IApplicationService
{
Task<Stream> GetAsync(GetStaticFileInput input);
}
}

14
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/OssContainerDto.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement
{
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; }
}
}

13
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/OssContainersResultDto.cs

@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement
{
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>();
}
}

16
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/OssObjectDto.cs

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement
{
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; }
}
}

15
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application.Contracts/LINGYUN/Abp/FileManagement/OssObjectsResultDto.cs

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement
{
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>();
}
}

4
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN.Abp.FileManagement.Application.csproj

@ -7,6 +7,10 @@
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="4.2.1" />
</ItemGroup>
<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" />

13
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/AbpFileManagementApplicationModule.cs

@ -1,12 +1,23 @@
using Volo.Abp.Modularity;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
using Microsoft.Extensions.DependencyInjection;
namespace LINGYUN.Abp.FileManagement
{
[DependsOn(
typeof(AbpAutoMapperModule),
typeof(AbpFileManagementDomainModule),
typeof(AbpFileManagementApplicationContractsModule))]
public class AbpFileManagementApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpFileManagementApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<FileManagementApplicationAutoMapperProfile>(validate: true);
});
}
}
}

17
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/FileManagementApplicationAutoMapperProfile.cs

@ -0,0 +1,17 @@
using AutoMapper;
namespace LINGYUN.Abp.FileManagement
{
public class FileManagementApplicationAutoMapperProfile : Profile
{
public FileManagementApplicationAutoMapperProfile()
{
CreateMap<OssContainer, OssContainerDto>();
CreateMap<OssObject, OssObjectDto>()
.ForMember(dto => dto.Path, map => map.MapFrom(src => src.Prefix));
CreateMap<GetOssContainersResponse, OssContainersResultDto>();
CreateMap<GetOssObjectsResponse, OssObjectsResultDto>();
}
}
}

10
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/FileSystemAppService.cs

@ -16,10 +16,10 @@ namespace LINGYUN.Abp.FileManagement
[Authorize(AbpFileManagementPermissions.FileSystem.Default)]
public class FileSystemAppService : FileManagementApplicationServiceBase, IFileSystemAppService
{
protected IBlobContainer<FileSystemContainer> BlobContainer { get; }
protected IBlobContainer<AbpFileManagementContainer> BlobContainer { get; }
protected IBlobContainerConfigurationProvider BlobContainerConfigurationProvider { get; }
public FileSystemAppService(
IBlobContainer<FileSystemContainer> blobContainer,
IBlobContainer<AbpFileManagementContainer> blobContainer,
IBlobContainerConfigurationProvider blobContainerConfigurationProvider)
{
BlobContainer = blobContainer;
@ -373,7 +373,7 @@ namespace LINGYUN.Abp.FileManagement
blobPath = Path.Combine(blobPath, "tenants", CurrentTenant.Id.Value.ToString("D"));
}
// 去除完整路径中的容器根目录
var containerName = BlobContainerNameAttribute.GetContainerName<FileSystemContainer>();
var containerName = BlobContainerNameAttribute.GetContainerName<AbpFileManagementContainer>();
if (path.Contains(containerName))
{
blobPath = Path.Combine(blobPath, containerName);
@ -421,7 +421,7 @@ namespace LINGYUN.Abp.FileManagement
{
blobPath = Path.Combine(blobPath, "tenants", CurrentTenant.Id.Value.ToString("D"));
}
var containerName = BlobContainerNameAttribute.GetContainerName<FileSystemContainer>();
var containerName = BlobContainerNameAttribute.GetContainerName<AbpFileManagementContainer>();
blobPath = Path.Combine(blobPath, containerName);
@ -436,7 +436,7 @@ namespace LINGYUN.Abp.FileManagement
protected virtual FileSystemBlobProviderConfiguration GetFileSystemBlobProviderConfiguration()
{
var blobConfiguration = BlobContainerConfigurationProvider
.Get<FileSystemContainer>();
.Get<AbpFileManagementContainer>();
return blobConfiguration.GetFileSystemConfiguration();
}

67
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/OssContainerAppService.cs

@ -0,0 +1,67 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.FileManagement
{
public class OssContainerAppService : FileManagementApplicationServiceBase, IOssContainerAppService
{
protected IOssContainerFactory OssContainerFactory { get; }
public OssContainerAppService(
IOssContainerFactory ossContainerFactory)
{
OssContainerFactory = ossContainerFactory;
}
public virtual async Task<OssContainerDto> CreateAsync(string name)
{
var oss = CreateOssContainer();
var container = await oss.CreateAsync(name);
return ObjectMapper.Map<OssContainer, OssContainerDto>(container);
}
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();
}
}
}

100
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/OssObjectAppService.cs

@ -0,0 +1,100 @@
using LINGYUN.Abp.FileManagement.Settings;
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.IO;
using Volo.Abp.Settings;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.FileManagement
{
public class OssObjectAppService : FileManagementApplicationServiceBase, IOssObjectAppService
{
protected IOssContainerFactory OssContainerFactory { get; }
public OssObjectAppService(
IOssContainerFactory ossContainerFactory)
{
OssContainerFactory = ossContainerFactory;
}
public virtual async Task<OssObjectDto> CreateAsync(CreateOssObjectInput input)
{
if (!input.Content.IsNullOrEmpty())
{
// 检查文件大小
var fileSizeLimited = await SettingProvider
.GetAsync(
AbpFileManagementSettingNames.FileLimitLength,
AbpFileManagementSettingNames.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(AbpFileManagementSettingNames.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);
}
public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input)
{
var oss = CreateOssContainer();
await oss.BulkDeleteObjectsAsync(input.Bucket, input.Objects, input.Path);
}
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})
});
}
}
}

31
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Application/LINGYUN/Abp/FileManagement/StaticFilesAppService.cs

@ -0,0 +1,31 @@
using System.IO;
using System.Threading.Tasks;
using System.Web;
namespace LINGYUN.Abp.FileManagement
{
public class StaticFilesAppService : FileManagementApplicationServiceBase, IStaticFilesAppService
{
protected IOssContainerFactory OssContainerFactory { get; }
public StaticFilesAppService(
IOssContainerFactory ossContainerFactory)
{
OssContainerFactory = ossContainerFactory;
}
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;
}
}
}

6
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/AbpFileManagementDomainSharedModule.cs

@ -1,5 +1,6 @@
using LINGYUN.Abp.FileManagement.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Volo.Abp.Validation.Localization;
@ -25,6 +26,11 @@ namespace LINGYUN.Abp.FileManagement
typeof(AbpValidationResource)
).AddVirtualJson("/LINGYUN/Abp/FileManagement/Localization/Resources");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace(FileManagementErrorCodes.Namespace, typeof(AbpFileManagementResource));
});
}
}
}

19
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/FileManagementErrorCodes.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace LINGYUN.Abp.FileManagement
{
public static class FileManagementErrorCodes
{
public const string Namespace = "Abp.FileManagement";
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";
}
}

6
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/en.json

@ -1,6 +1,12 @@
{
"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!",
"Permission:FileManagement": "File management",
"Permission:FileSystem": "File system",
"Permission:FileManager": "Files",

6
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Localization/Resources/zh-Hans.json

@ -1,6 +1,12 @@
{
"culture": "zh-Hans",
"texts": {
"Abp.FileManagement:010001": "不能删除存在多个对象的容器!",
"Abp.FileManagement:010402": "容器名称已经存在!",
"Abp.FileManagement:010404": "未能找到查询的容器!",
"Abp.FileManagement:020001": "不能删除存在多个子级的对象!",
"Abp.FileManagement:020402": "对象名称已经存在!",
"Abp.FileManagement:020404": "未能找到查询的对象!",
"Permission:FileManagement": "文件管理",
"Permission:FileSystem": "文件系统",
"Permission:FileManager": "文件",

4
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/LINGYUN/Abp/FileManagement/Settings/AbpFileManagementSettingNames.cs

@ -4,6 +4,10 @@
{
public const string GroupName = "Abp.FileManagement";
/// <summary>
/// 下载分包大小
/// </summary>
public const string DownloadPackageSize = GroupName + ".DownloadPackageSize";
/// <summary>
/// 文件限制长度
/// </summary>
public const string FileLimitLength = GroupName + ".FileLimitLength";

12
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain.Shared/System/IO/StreamExtensions.cs

@ -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);
}
}
}

3
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN.Abp.FileManagement.Domain.csproj

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>

2
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/FileSystemContainer.cs → aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/AbpFileManagementContainer.cs

@ -3,7 +3,7 @@
namespace LINGYUN.Abp.FileManagement
{
[BlobContainerName("abp-file-management")]
public class FileSystemContainer
public class AbpFileManagementContainer
{
}
}

26
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/BulkDeleteObjectRequest.cs

@ -0,0 +1,26 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using Volo.Abp;
namespace LINGYUN.Abp.FileManagement
{
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;
}
}
}

35
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/CreateOssObjectRequest.cs

@ -0,0 +1,35 @@
using JetBrains.Annotations;
using System;
using System.IO;
using Volo.Abp;
namespace LINGYUN.Abp.FileManagement
{
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;
}
}
}

18
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssContainersRequest.cs

@ -0,0 +1,18 @@
namespace LINGYUN.Abp.FileManagement
{
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;
}
}
}

28
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssContainersResponse.cs

@ -0,0 +1,28 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement
{
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;
}
}
}

31
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssObjectRequest.cs

@ -0,0 +1,31 @@
using JetBrains.Annotations;
using Volo.Abp;
namespace LINGYUN.Abp.FileManagement
{
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;
}
}
}

32
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssObjectsRequest.cs

@ -0,0 +1,32 @@
using JetBrains.Annotations;
using Volo.Abp;
namespace LINGYUN.Abp.FileManagement
{
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;
}
}
}

33
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/GetOssObjectsResponse.cs

@ -0,0 +1,33 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement
{
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;
}
}
}

72
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/IOssContainer.cs

@ -0,0 +1,72 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.FileManagement
{
/// <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);
}
}

79
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/IOssContainerExtensions.cs

@ -0,0 +1,79 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.FileManagement
{
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));
}
}
}

18
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/IOssContainerFactory.cs

@ -0,0 +1,18 @@
namespace LINGYUN.Abp.FileManagement
{
/// <summary>
/// Oss容器构建工厂
/// </summary>
public interface IOssContainerFactory
{
IOssContainer Create();
}
/// <summary>
/// Oss容器构建工厂
/// </summary>
public interface IOssContainerFactory<TConfiguration>
{
IOssContainer Create(TConfiguration configuration);
}
}

31
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/OssContainer.cs

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement
{
/// <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>();
}
}
}

50
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/OssObject.cs

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace LINGYUN.Abp.FileManagement
{
/// <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);
}
}
}
}

27
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.Domain/LINGYUN/Abp/FileManagement/OssObjectComparer.cs

@ -0,0 +1,27 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement
{
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);
}
}
}

16
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp.csproj

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.FileSystem\LINGYUN.Abp.FileManagement.FileSystem.csproj" />
</ItemGroup>
</Project>

16
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp/LINGYUN/Abp/FileManagement/FileSystem/ImageSharp/AbpFileManagementFileSystemImageSharpModule.cs

@ -0,0 +1,16 @@
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.FileManagement.FileSystem.ImageSharp
{
[DependsOn(typeof(AbpFileManagementFileSystemModule))]
public class AbpFileManagementFileSystemImageSharpModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<FileSystemOssOptions>(options =>
{
options.AddProcesser(new ImageSharpProcesserContributor());
});
}
}
}

118
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp/LINGYUN/Abp/FileManagement/FileSystem/ImageSharp/ImageSharpFileSystemOssObjectProcesser.cs

@ -0,0 +1,118 @@
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Processing;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace LINGYUN.Abp.FileManagement.FileSystem.ImageSharp
{
public class ImageSharpProcesserContributor : IFileSystemOssObjectProcesserContributor
{
protected static readonly string[] ImageTypes = new string[]
{
"6677",// bmp
"7173",// gif
"13780",// png
"255216"// jpg
};
public virtual async Task ProcessAsync(FileSystemOssObjectContext context)
{
var bytes = await context.OssObject.Content.GetAllBytesAsync();
if (IsImage(bytes))
{
var args = context.Process.Split(',');
if (DrawGraphics(bytes, args, out Stream content))
{
context.SetContent(content);
}
}
}
protected virtual bool DrawGraphics(byte[] fileBytes, string[] args, out Stream content)
{
using var image = Image.Load(fileBytes, out IImageFormat format);
// 大小
var width = GetInt32Prarm(args, "w_");
var height = GetInt32Prarm(args, "h_");
if (!width.IsNullOrWhiteSpace() &&
!height.IsNullOrWhiteSpace())
{
image.Mutate(x => x.Resize(int.Parse(width), int.Parse(height)));
}
// 水印
//var txt = GetString(args, "t_");
//if (!txt.IsNullOrWhiteSpace())
//{
// FontCollection fonts = new FontCollection();
// FontFamily fontfamily = fonts.Install("本地字体.TTF");
// var font = new Font(fontfamily, 20, FontStyle.Bold);
// var size = TextMeasurer.Measure(txt, new RendererOptions(font));
// image.Mutate(x => x.DrawText(txt, font, Color.WhiteSmoke,
// new PointF(image.Width - size.Width - 3, image.Height - size.Height - 3)));
//}
// TODO: 其他处理参数及现有的优化
var imageStream = new MemoryStream();
var encoder = image.GetConfiguration().ImageFormatsManager.FindEncoder(format);
image.Save(imageStream, encoder);
imageStream.Seek(0, SeekOrigin.Begin);
content = imageStream;
return true;
}
private static bool IsImage(byte[] fileBytes)
{
if (fileBytes.IsNullOrEmpty())
{
return false;
}
string fileclass = "";
for (int i = 0; i < 2; i++)
{
fileclass += fileBytes[i].ToString();
}
return ImageTypes.Any(type => type.Equals(fileclass));
}
private static string GetString(string[] args, string key)
{
if (!args.Any())
{
return null;
}
return args
.Where(arg => arg.StartsWith(key))
.Select(arg => arg.Substring(key.Length))
.FirstOrDefault();
}
private static string GetInt32Prarm(string[] args, string key)
{
if (!args.Any())
{
return null;
}
return args
.Where(arg => arg.StartsWith(key))
.Select(arg => arg.Substring(key.Length))
.FirstOrDefault(arg => int.TryParse(arg, out _));
}
}
}

15
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem.ImageSharp/README.md

@ -0,0 +1,15 @@
# LINGYUN.Abp.FileManagement.FileSystem.ImageSharp
本地文件系统oss对象ImageSharp图形处理接口
## 配置使用
模块按需引用
```csharp
[DependsOn(typeof(AbpFileManagementFileSystemImageSharpModule))]
public class YouProjectModule : AbpModule
{
// other
}
```

17
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN.Abp.FileManagement.FileSystem.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<LangVersion>8.0</LangVersion>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.BlobStoring.FileSystem" Version="4.2.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.FileManagement.Domain\LINGYUN.Abp.FileManagement.Domain.csproj" />
</ItemGroup>
</Project>

17
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/AbpFileManagementFileSystemModule.cs

@ -0,0 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
[DependsOn(
typeof(AbpBlobStoringFileSystemModule),
typeof(AbpFileManagementDomainModule))]
public class AbpFileManagementFileSystemModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTransient<IOssContainerFactory, FileSystemOssContainerFactory>();
}
}
}

512
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssContainer.cs

@ -0,0 +1,512 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.MultiTenancy;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.IO;
using Volo.Abp;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
/// <summary>
/// Oss容器的本地文件系统实现
/// </summary>
internal class FileSystemOssContainer : IOssContainer
{
protected ICurrentTenant CurrentTenant { get; }
protected IHostEnvironment Environment { get; }
protected IBlobFilePathCalculator FilePathCalculator { get; }
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
protected IServiceProvider ServiceProvider { get; }
protected FileSystemOssOptions Options { get; }
public FileSystemOssContainer(
ICurrentTenant currentTenant,
IHostEnvironment environment,
IServiceProvider serviceProvider,
IBlobFilePathCalculator blobFilePathCalculator,
IBlobContainerConfigurationProvider configurationProvider,
IOptions<FileSystemOssOptions> options)
{
CurrentTenant = currentTenant;
Environment = environment;
ServiceProvider = serviceProvider;
FilePathCalculator = blobFilePathCalculator;
ConfigurationProvider = configurationProvider;
Options = options.Value;
}
public virtual Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request)
{
var filesPath = request.Objects.Select(x => CalculateFilePath(request.Bucket, x));
foreach (var file in filesPath)
{
if (File.Exists(file))
{
File.Delete(file);
}
}
return Task.CompletedTask;
}
public virtual Task<OssContainer> CreateAsync(string name)
{
var filePath = CalculateFilePath(name);
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
var directoryInfo = new DirectoryInfo(filePath);
var container = new OssContainer(
directoryInfo.Name,
directoryInfo.CreationTime,
0L,
directoryInfo.LastWriteTime,
new Dictionary<string, string>
{
{ "LastAccessTime", directoryInfo.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss") }
});
return Task.FromResult(container);
}
public virtual async Task<OssObject> CreateObjectAsync(CreateOssObjectRequest request)
{
var objectPath = !request.Path.IsNullOrWhiteSpace()
? request.Path.EnsureEndsWith('/')
: "";
var objectName = objectPath.IsNullOrWhiteSpace()
? request.Object
: objectPath + request.Object;
var filePath = CalculateFilePath(request.Bucket, objectName);
if (!request.Content.IsNullOrEmpty())
{
if (File.Exists(filePath))
{
throw new BusinessException(code: FileManagementErrorCodes.ObjectAlreadyExists);
// throw new OssObjectAlreadyExistsException($"Can't not put object {objectName} in container {request.Bucket}, Because a file with the same name already exists in the directory!");
}
DirectoryHelper.CreateIfNotExists(Path.GetDirectoryName(filePath));
using (var fileStream = File.Open(filePath, FileMode.CreateNew, FileAccess.Write))
{
await request.Content.CopyToAsync(fileStream);
await fileStream.FlushAsync();
}
var fileInfo = new FileInfo(filePath);
var ossObject = new OssObject(
fileInfo.Name,
objectPath,
fileInfo.CreationTime,
fileInfo.Length,
fileInfo.LastWriteTime,
new Dictionary<string, string>
{
{ "IsReadOnly", fileInfo.IsReadOnly.ToString() },
{ "LastAccessTime", fileInfo.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss") }
})
{
FullName = fileInfo.FullName.Replace(Environment.ContentRootPath, "")
};
ossObject.SetContent(request.Content);
return ossObject;
}
else
{
if (Directory.Exists(filePath))
{
throw new BusinessException(code: FileManagementErrorCodes.ObjectAlreadyExists);
// throw new OssObjectAlreadyExistsException($"Can't not put object {objectName} in container {request.Bucket}, Because a file with the same name already exists in the directory!");
}
Directory.CreateDirectory(filePath);
var directoryInfo = new DirectoryInfo(filePath);
var ossObject = new OssObject(
directoryInfo.Name.EnsureEndsWith('/'),
objectPath,
directoryInfo.CreationTime,
0L,
directoryInfo.LastWriteTime,
new Dictionary<string, string>
{
{ "LastAccessTime", directoryInfo.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss") }
},
true)
{
FullName = directoryInfo.FullName.Replace(Environment.ContentRootPath, "")
};
ossObject.SetContent(request.Content);
return ossObject;
}
}
public virtual Task DeleteAsync(string name)
{
var filePath = CalculateFilePath(name);
if (!Directory.Exists(filePath))
{
// 非空目录无法删除
if (Directory.GetFiles(filePath).Length > 0)
{
throw new BusinessException(code: FileManagementErrorCodes.ContainerDeleteWithNotEmpty);
// throw new ContainerDeleteWithNotEmptyException("00101", $"Can't not delete container {name}, because it is not empty!");
}
Directory.Delete(filePath);
}
return Task.CompletedTask;
}
public virtual Task DeleteObjectAsync(GetOssObjectRequest request)
{
var objectName = request.Path.IsNullOrWhiteSpace()
? request.Object
: request.Path.EnsureEndsWith('/') + request.Object;
var filePath = CalculateFilePath(request.Bucket, objectName);
if (!File.Exists(filePath))
{
File.Delete(filePath);
}
else if (Directory.Exists(filePath))
{
if (Directory.GetFiles(filePath).Length > 0)
{
throw new BusinessException(code: FileManagementErrorCodes.ObjectDeleteWithNotEmpty);
}
Directory.Delete(filePath);
}
return Task.CompletedTask;
}
public virtual Task<bool> ExistsAsync(string name)
{
var filePath = CalculateFilePath(name);
return Task.FromResult(Directory.Exists(filePath));
}
public virtual Task<OssContainer> GetAsync(string name)
{
var filePath = CalculateFilePath(name);
if (!Directory.Exists(filePath))
{
throw new BusinessException(code: FileManagementErrorCodes.ContainerNotFound);
// throw new ContainerNotFoundException($"Can't not found container {name} in file system");
}
var directoryInfo = new DirectoryInfo(filePath);
var container = new OssContainer(
directoryInfo.Name,
directoryInfo.CreationTime,
0L,
directoryInfo.LastWriteTime,
new Dictionary<string, string>
{
{ "LastAccessTime", directoryInfo.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss") }
});
return Task.FromResult(container);
}
public virtual async Task<OssObject> GetObjectAsync(GetOssObjectRequest request)
{
var objectPath = !request.Path.IsNullOrWhiteSpace()
? request.Path.EnsureEndsWith('/')
: "";
var objectName = objectPath.IsNullOrWhiteSpace()
? request.Object
: objectPath + request.Object;
var filePath = CalculateFilePath(request.Bucket, objectName);
if (!File.Exists(filePath))
{
if (!Directory.Exists(filePath))
{
throw new BusinessException(code: FileManagementErrorCodes.ObjectNotFound);
// throw new ContainerNotFoundException($"Can't not found object {objectName} in container {request.Bucket} with file system");
}
var directoryInfo = new DirectoryInfo(filePath);
var ossObject = new OssObject(
directoryInfo.Name.EnsureEndsWith('/'),
objectPath,
directoryInfo.CreationTime,
0L,
directoryInfo.LastWriteTime,
new Dictionary<string, string>
{
{ "LastAccessTime", directoryInfo.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss") }
},
true)
{
FullName = directoryInfo.FullName.Replace(Environment.ContentRootPath, "")
};
return ossObject;
}
else
{
var fileInfo = new FileInfo(filePath);
var ossObject = new OssObject(
fileInfo.Name,
objectPath,
fileInfo.CreationTime,
fileInfo.Length,
fileInfo.LastWriteTime,
new Dictionary<string, string>
{
{ "IsReadOnly", fileInfo.IsReadOnly.ToString() },
{ "LastAccessTime", fileInfo.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss") }
})
{
FullName = fileInfo.FullName.Replace(Environment.ContentRootPath, "")
};
using (var fileStream = File.OpenRead(filePath))
{
var memoryStream = new MemoryStream();
await fileStream.CopyToAsync(memoryStream);
ossObject.SetContent(memoryStream);
if (!request.Process.IsNullOrWhiteSpace())
{
using var serviceScope = ServiceProvider.CreateScope();
var context = new FileSystemOssObjectContext(request.Process, ossObject, serviceScope.ServiceProvider);
foreach (var processer in Options.Processers)
{
await processer.ProcessAsync(context);
if (context.Handled)
{
ossObject.SetContent(context.Content);
break;
}
}
}
}
return ossObject;
}
}
public virtual Task<GetOssContainersResponse> GetListAsync(GetOssContainersRequest request)
{
// 不传递Bucket 检索根目录的Bucket
var filePath = CalculateFilePath(null);
// 获取根目录
var directories = Directory.GetDirectories(filePath, request.Prefix ?? "*.*");
// 排序目录
Array.Sort(directories, delegate (string x, string y)
{
return x.CompareTo(y);
});
var spiltDirectories = directories;
// 计算标记的位置进行截断
if (!request.Marker.IsNullOrWhiteSpace())
{
var markIndex = directories.FindIndex(x => x.EndsWith(request.Marker));
if (markIndex < 0)
{
directories = new string[0];
}
else
{
var markDirectories = new string[directories.Length - markIndex];
Array.Copy(directories, markIndex, markDirectories, 0, markDirectories.Length);
directories = markDirectories;
}
}
// 需要截断最大的容器集合
if (request.MaxKeys.HasValue)
{
spiltDirectories = directories.Take(request.MaxKeys ?? directories.Length).ToArray();
}
var nextDirectory = spiltDirectories.Length < directories.Length ? directories[spiltDirectories.Length] : "";
if (!nextDirectory.IsNullOrWhiteSpace())
{
// 下一个标记的目录名称
nextDirectory = new DirectoryInfo(nextDirectory).Name;
}
// 容器对应的目录信息集合
var directoryInfos = spiltDirectories.Select(x => new DirectoryInfo(x));
// 返回Oss容器描述集合
var response = new GetOssContainersResponse(
request.Prefix,
request.Marker,
nextDirectory,
directories.Length,
directoryInfos.Select(x => new OssContainer(
x.Name,
x.CreationTime,
0L,
x.LastWriteTime,
new Dictionary<string, string>
{
{ "LastAccessTime", x.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss") }
}))
.ToList());
return Task.FromResult(response);
}
public virtual Task<GetOssObjectsResponse> GetObjectsAsync(GetOssObjectsRequest request)
{
// 先定位检索的目录
var filePath = CalculateFilePath(request.BucketName, request.Prefix);
if (!Directory.Exists(filePath))
{
throw new BusinessException(code: FileManagementErrorCodes.ContainerNotFound);
// throw new ContainerNotFoundException($"Can't not found container {request.BucketName} in file system");
}
// 目录也属于Oss对象,需要抽象的文件系统集合来存储
var fileSystemNames = Directory.GetFileSystemEntries(filePath);
int maxFilesCount = fileSystemNames.Length;
// 排序所有文件与目录
Array.Sort(fileSystemNames, delegate (string x, string y)
{
// 检索的是文件系统名称
// 需要判断是否为文件夹进行升序排序
// 参考 OssObjectComparer
var xFolder = Directory.Exists(x);
var yFolder = Directory.Exists(y);
if (xFolder && yFolder)
{
return x.CompareTo(y);
}
if (xFolder && !yFolder)
{
return -1;
}
if (!xFolder && yFolder)
{
return 1;
}
return x.CompareTo(y);
});
// 需要计算从哪个位置截断
int markIndex = 0;
if (!request.Marker.IsNullOrWhiteSpace())
{
markIndex = fileSystemNames.FindIndex(x => x.EndsWith(request.Marker));
if (markIndex < 0)
{
markIndex = 0;
}
}
// 需要截断Oss对象列表
var copyFileSystemNames = fileSystemNames;
if (markIndex > 0)
{
copyFileSystemNames = fileSystemNames[(markIndex+1)..];
}
// 截取指定数量的Oss对象
int maxResultCount = request.MaxKeys ?? 10;
// Oss对象信息集合
var fileSystems = copyFileSystemNames
.Take(maxResultCount)
.Select<string, FileSystemInfo>(file =>
{
if (File.Exists(file))
{
return new FileInfo(file);
}
return new DirectoryInfo(file);
})
.ToArray();
// 计算下一页起始标记文件/目录名称
var nextMarkerIndex = fileSystemNames.FindIndex(x => x.EndsWith(fileSystems[fileSystems.Length - 1].Name));
string nextMarker = "";
if (nextMarkerIndex >=0 && nextMarkerIndex + 1 < fileSystemNames.Length)
{
nextMarker = fileSystemNames[nextMarkerIndex + 1];
nextMarker = File.Exists(nextMarker)
? new FileInfo(nextMarker).Name
: new DirectoryInfo(nextMarker).Name.EnsureEndsWith('/');
}
// 返回Oss对象描述集合
var response = new GetOssObjectsResponse(
request.BucketName,
request.Prefix,
request.Marker,
nextMarker,
"/", // 文件系统目录分隔符
fileSystemNames.Length,
fileSystems.Select(x => new OssObject(
(x is DirectoryInfo) ? x.Name.EnsureEndsWith('/') : x.Name,
request.Prefix,
x.CreationTime,
(x as FileInfo)?.Length ?? 0L,
x.LastWriteTime,
new Dictionary<string, string>
{
{ "LastAccessTime", x.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss") }
},
x is DirectoryInfo)
{
FullName = x.FullName.Replace(Environment.ContentRootPath, "")
})
.ToList());
return Task.FromResult(response);
}
protected virtual FileSystemBlobProviderConfiguration GetFileSystemConfiguration()
{
var configuration = ConfigurationProvider.Get<AbpFileManagementContainer>();
var fileSystemConfiguration = configuration.GetFileSystemConfiguration();
return fileSystemConfiguration;
}
protected virtual string CalculateFilePath(string bucketName, string blobName = "")
{
var fileSystemConfiguration = GetFileSystemConfiguration();
var blobPath = fileSystemConfiguration.BasePath;
if (CurrentTenant.Id == null)
{
blobPath = Path.Combine(blobPath, "host");
}
else
{
blobPath = Path.Combine(blobPath, "tenants", CurrentTenant.Id.Value.ToString("D"));
}
if (fileSystemConfiguration.AppendContainerNameToBasePath &&
!bucketName.IsNullOrWhiteSpace())
{
blobPath = Path.Combine(blobPath, bucketName);
}
if (!blobName.IsNullOrWhiteSpace())
{
blobPath = Path.Combine(blobPath, blobName);
}
return blobPath;
}
}
}

46
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssContainerFactory.cs

@ -0,0 +1,46 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
public class FileSystemOssContainerFactory : IOssContainerFactory
{
protected ICurrentTenant CurrentTenant { get; }
protected IHostEnvironment Environment { get; }
protected IServiceProvider ServiceProvider { get; }
protected IBlobFilePathCalculator FilePathCalculator { get; }
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
protected IOptions<FileSystemOssOptions> Options { get; }
public FileSystemOssContainerFactory(
ICurrentTenant currentTenant,
IHostEnvironment environment,
IServiceProvider serviceProvider,
IBlobFilePathCalculator blobFilePathCalculator,
IBlobContainerConfigurationProvider configurationProvider,
IOptions<FileSystemOssOptions> options)
{
Environment = environment;
CurrentTenant = currentTenant;
ServiceProvider = serviceProvider;
FilePathCalculator = blobFilePathCalculator;
ConfigurationProvider = configurationProvider;
Options = options;
}
public IOssContainer Create()
{
return new FileSystemOssContainer(
CurrentTenant,
Environment,
ServiceProvider,
FilePathCalculator,
ConfigurationProvider,
Options);
}
}
}

32
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssObjectContext.cs

@ -0,0 +1,32 @@
using System;
using System.IO;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
public class FileSystemOssObjectContext : IServiceProviderAccessor
{
public string Process { get; }
public OssObject OssObject { get; }
public bool Handled { get; private set; }
public Stream Content { get; private set; }
public IServiceProvider ServiceProvider { get; }
public FileSystemOssObjectContext(
string process,
OssObject ossObject,
IServiceProvider serviceProvider)
{
Process = process;
OssObject = ossObject;
ServiceProvider = serviceProvider;
}
public void SetContent(Stream content)
{
Content = content;
Content.Seek(0, SeekOrigin.Begin);
Handled = true;
}
}
}

19
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssOptions.cs

@ -0,0 +1,19 @@
using JetBrains.Annotations;
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
public class FileSystemOssOptions
{
[NotNull]
public List<IFileSystemOssObjectProcesserContributor> Processers { get; }
public FileSystemOssOptions()
{
Processers = new List<IFileSystemOssObjectProcesserContributor>
{
new NoneFileSystemOssObjectProcesser()
};
}
}
}

15
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssOptionsExtensions.cs

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
public static class FileSystemOssOptionsExtensions
{
public static void AddProcesser<TProcesserContributor>(
this FileSystemOssOptions options,
TProcesserContributor contributor)
where TProcesserContributor : IFileSystemOssObjectProcesserContributor
{
options.Processers.InsertBefore((x) => x is NoneFileSystemOssObjectProcesser, contributor);
}
}
}

18
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/FileSystemOssProviderArgs.cs

@ -0,0 +1,18 @@
using System.Threading;
using Volo.Abp.BlobStoring;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
public class FileSystemOssProviderArgs : BlobProviderArgs
{
public FileSystemOssProviderArgs(
string containerName,
BlobContainerConfiguration configuration,
string blobName,
CancellationToken cancellationToken = default)
: base(containerName, configuration, blobName, cancellationToken)
{
}
}
}

10
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/IFileSystemOssObjectProcesserContributor.cs

@ -0,0 +1,10 @@
using System.IO;
using System.Threading.Tasks;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
public interface IFileSystemOssObjectProcesserContributor
{
Task ProcessAsync(FileSystemOssObjectContext context);
}
}

15
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/LINGYUN/Abp/FileManagement/FileSystem/NoneFileSystemOssObjectProcesser.cs

@ -0,0 +1,15 @@
using System.IO;
using System.Threading.Tasks;
namespace LINGYUN.Abp.FileManagement.FileSystem
{
public class NoneFileSystemOssObjectProcesser : IFileSystemOssObjectProcesserContributor
{
public Task ProcessAsync(FileSystemOssObjectContext context)
{
context.SetContent(context.OssObject.Content);
return Task.CompletedTask;
}
}
}

15
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.FileSystem/README.md

@ -0,0 +1,15 @@
# LINGYUN.Abp.FileManagement.FileSystem
本地文件系统oss容器接口
## 配置使用
模块按需引用
```csharp
[DependsOn(typeof(AbpFileManagementFileSystemModule))]
public class YouProjectModule : AbpModule
{
// other
}
```

56
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/OssContainerController.cs

@ -0,0 +1,56 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
namespace LINGYUN.Abp.FileManagement
{
[RemoteService(Name = "AbpFileManagement")]
[Area("file-management")]
[Route("api/file-management/containes")]
public class OssContainerController : AbpController, IOssContainerAppService
{
protected IOssContainerAppService OssContainerAppService { get; }
public OssContainerController(
IOssContainerAppService ossContainerAppService)
{
OssContainerAppService = ossContainerAppService;
}
[HttpPost]
[Route("{name}")]
public virtual async Task<OssContainerDto> CreateAsync(string name)
{
return await OssContainerAppService.CreateAsync(name);
}
[HttpDelete]
[Route("{name}")]
public virtual async Task DeleteAsync(string name)
{
await OssContainerAppService.DeleteAsync(name);
}
[HttpGet]
[Route("{name}")]
public virtual async Task<OssContainerDto> GetAsync(string name)
{
return await OssContainerAppService.GetAsync(name);
}
[HttpGet]
public virtual async Task<OssContainersResultDto> GetListAsync(GetOssContainersInput input)
{
return await OssContainerAppService.GetListAsync(input);
}
[HttpGet]
[Route("objects")]
public virtual async Task<OssObjectsResultDto> GetObjectListAsync(GetOssObjectsInput input)
{
return await OssContainerAppService.GetObjectListAsync(input);
}
}
}

81
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/OssObjectController.cs

@ -0,0 +1,81 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.FileManagement
{
[RemoteService(Name = "AbpFileManagement")]
[Area("file-management")]
[Route("api/file-management/objects")]
public class OssObjectController : AbpController, IOssObjectAppService
{
protected IOssObjectAppService OssObjectAppService { get; }
public OssObjectController(
IOssObjectAppService ossObjectAppService)
{
OssObjectAppService = ossObjectAppService;
}
[HttpPost]
public virtual async Task<OssObjectDto> CreateAsync(CreateOssObjectInput input)
{
return await OssObjectAppService.CreateAsync(input);
}
[HttpPost]
[Route("upload")]
public virtual async Task<OssObjectDto> UploadAsync([FromForm] UploadOssObjectInput input)
{
var createOssObjectInput = new CreateOssObjectInput
{
Bucket = input.Bucket,
Path = input.Path,
Object = input.Name
};
if (input.File != null)
{
//if (input.File.Length <= 0)
//{
// ThrowValidationException(L["FileNotBeNullOrEmpty"], "File");
//}
createOssObjectInput.Object = input.File.FileName;
createOssObjectInput.Content = input.File.OpenReadStream();
}
return await OssObjectAppService.CreateAsync(createOssObjectInput);
}
[HttpDelete]
[Route("bulk-delete")]
public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input)
{
await OssObjectAppService.BulkDeleteAsync(input);
}
[HttpDelete]
public virtual async Task DeleteAsync(GetOssObjectInput input)
{
await OssObjectAppService.DeleteAsync(input);
}
[HttpGet]
public virtual async Task<OssObjectDto> GetAsync(GetOssObjectInput input)
{
return await OssObjectAppService.GetAsync(input);
}
private static void ThrowValidationException(string message, string memberName)
{
throw new AbpValidationException(message,
new List<ValidationResult>
{
new ValidationResult(message, new[] {memberName})
});
}
}
}

87
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/StaticFilesController.cs

@ -0,0 +1,87 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Http;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.FileManagement
{
[RemoteService(Name = "AbpFileManagement")]
[Area("file-management")]
[Route("api/files/static")]
public class StaticFilesController : AbpController
{
private readonly IOssObjectAppService _ossObjectAppService;
private readonly IStaticFilesAppService _staticFilesAppServic;
public StaticFilesController(
IOssObjectAppService ossObjectAppService,
IStaticFilesAppService staticFilesAppServic)
{
_ossObjectAppService = ossObjectAppService;
_staticFilesAppServic = staticFilesAppServic;
}
[HttpPost]
[Route("{bucket}")]
[Route("{bucket}/{path}")]
public virtual async Task<OssObjectDto> UploadAsync(string bucket, string path, [FromForm] IFormFile file)
{
if (file == null || file.Length <= 0)
{
ThrowValidationException(L["FileNotBeNullOrEmpty"], "File");
}
var createOssObjectInput = new CreateOssObjectInput
{
Bucket = bucket,
Path = path,
Object = file.FileName,
Content = file.OpenReadStream()
};
return await _ossObjectAppService.CreateAsync(createOssObjectInput);
}
[HttpGet]
[Route("{bucket}/{name}")]
[Route("{bucket}/{name}/{process}")]
[Route("{bucket}/p/{path}/{name}")]
[Route("{bucket}/p/{path}/{name}/{process}")]
public virtual async Task<IActionResult> GetAsync(string bucket, string path, string name, string process)
{
var input = new GetStaticFileInput
{
Bucket = bucket,
Name = name,
Path = path,
Process = process
};
var fileStream = await _staticFilesAppServic.GetAsync(input);
if (fileStream.IsNullOrEmpty())
{
return NotFound();
}
return File(
fileStream,
MimeTypes.GetByExtension(Path.GetExtension(input.Name))
);
}
private static void ThrowValidationException(string message, string memberName)
{
throw new AbpValidationException(message,
new List<ValidationResult>
{
new ValidationResult(message, new[] {memberName})
});
}
}
}

12
aspnet-core/modules/file-management/LINGYUN.Abp.FileManagement.HttpApi/LINGYUN/Abp/FileManagement/UploadOssObjectInput.cs

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Http;
namespace LINGYUN.Abp.FileManagement
{
public class UploadOssObjectInput
{
public string Bucket { get; set; }
public string Path { get; set; }
public string Name { get; set; }
public IFormFile File { get; set; }
}
}

BIN
aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/event-bus-cap.db

Binary file not shown.

34
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs

@ -3,6 +3,9 @@ using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling;
using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.FileManagement;
using LINGYUN.Abp.FileManagement.Aliyun;
using LINGYUN.Abp.FileManagement.FileSystem;
using LINGYUN.Abp.FileManagement.FileSystem.ImageSharp;
using LINGYUN.Abp.MultiTenancy.DbFinder;
using LINGYUN.Abp.Notifications;
using LINGYUN.Platform.EntityFrameworkCore;
@ -16,11 +19,14 @@ using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using StackExchange.Redis;
using System;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.MultiTenancy;
@ -35,7 +41,10 @@ using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Http.Client.IdentityModel.Web;
using Volo.Abp.Identity;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
@ -46,15 +55,13 @@ using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using Volo.Abp.Threading;
using Volo.Abp.VirtualFileSystem;
using Volo.Abp.Http.Client.IdentityModel.Web;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using System.Text.Encodings.Web;
using System.Text.Unicode;
namespace LINGYUN.Platform
{
[DependsOn(
// typeof(AbpFileManagementAliyunModule),
typeof(AbpFileManagementFileSystemModule), // 本地文件系统提供者模块
typeof(AbpFileManagementFileSystemImageSharpModule), // 本地文件系统图形处理模块
typeof(AbpFileManagementApplicationModule),
typeof(AbpFileManagementHttpApiModule),
typeof(PlatformApplicationModule),
@ -210,19 +217,6 @@ namespace LINGYUN.Platform
options.IsEnabled = true;
});
var tenantResolveCfg = configuration.GetSection("App:Domains");
if (tenantResolveCfg.Exists())
{
Configure<AbpTenantResolveOptions>(options =>
{
var domains = tenantResolveCfg.Get<string[]>();
foreach (var domain in domains)
{
options.AddDomainTenantResolver(domain);
}
});
}
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Platform";
@ -313,6 +307,8 @@ namespace LINGYUN.Platform
app.UseVirtualFiles();
// 本地化
app.UseAbpRequestLocalization();
// 多租户
app.UseMultiTenancy();
//路由
app.UseRouting();
// 认证
@ -322,8 +318,6 @@ namespace LINGYUN.Platform
app.UseJwtTokenMiddleware();
// 授权
app.UseAuthorization();
// 多租户
app.UseMultiTenancy();
// Swagger
app.UseSwagger();
// Swagger可视化界面

40
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/DomainTenantResolveContributor.cs

@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Text.Formatting;
namespace LINGYUN.Platform
{
public class DomainTenantResolveContributor : HttpTenantResolveContributorBase
{
public const string ContributorName = "Domain";
public override string Name => ContributorName;
private static readonly string[] ProtocolPrefixes = { "http://", "https://" };
private readonly string _domainFormat;
public DomainTenantResolveContributor(string domainFormat)
{
_domainFormat = domainFormat.RemovePreFix(ProtocolPrefixes);
}
protected override Task<string> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
{
if (!httpContext.Request.Host.HasValue)
{
return Task.FromResult<string>(null);
}
var hostName = httpContext.Request.Host.Value.RemovePreFix(ProtocolPrefixes);
var extractResult = FormattedStringValueExtracter.Extract(hostName, _domainFormat, ignoreCase: true);
context.Handled = true;
return Task.FromResult(extractResult.IsMatch ? extractResult.Matches[0].Value : null);
}
}
}

50
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/HeaderTenantResolveContributor.cs

@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Platform
{
public class HeaderTenantResolveContributor : HttpTenantResolveContributorBase
{
public const string ContributorName = "Header";
public override string Name => ContributorName;
protected override Task<string> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
{
if (httpContext.Request.Headers.IsNullOrEmpty())
{
return Task.FromResult((string)null);
}
var tenantIdKey = context.GetAbpAspNetCoreMultiTenancyOptions().TenantKey;
var tenantIdHeader = httpContext.Request.Headers[tenantIdKey];
if (tenantIdHeader == string.Empty || tenantIdHeader.Count < 1)
{
return Task.FromResult((string)null);
}
if (tenantIdHeader.Count > 1)
{
Log(context, $"HTTP request includes more than one {tenantIdKey} header value. First one will be used. All of them: {tenantIdHeader.JoinAsString(", ")}");
}
return Task.FromResult(tenantIdHeader.First());
}
protected virtual void Log(ITenantResolveContext context, string text)
{
context
.ServiceProvider
.GetRequiredService<ILogger<HeaderTenantResolveContributor>>()
.LogWarning(text);
}
}
}

3
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj

@ -54,7 +54,10 @@
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.EventBus.CAP\LINGYUN.Abp.EventBus.CAP.csproj" />
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.ExceptionHandling.Emailing\LINGYUN.Abp.ExceptionHandling.Emailing.csproj" />
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" />
<ProjectReference Include="..\..\..\modules\file-management\LINGYUN.Abp.FileManagement.Aliyun\LINGYUN.Abp.FileManagement.Aliyun.csproj" />
<ProjectReference Include="..\..\..\modules\file-management\LINGYUN.Abp.FileManagement.Application\LINGYUN.Abp.FileManagement.Application.csproj" />
<ProjectReference Include="..\..\..\modules\file-management\LINGYUN.Abp.FileManagement.FileSystem.ImageSharp\LINGYUN.Abp.FileManagement.FileSystem.ImageSharp.csproj" />
<ProjectReference Include="..\..\..\modules\file-management\LINGYUN.Abp.FileManagement.FileSystem\LINGYUN.Abp.FileManagement.FileSystem.csproj" />
<ProjectReference Include="..\..\..\modules\file-management\LINGYUN.Abp.FileManagement.HttpApi\LINGYUN.Abp.FileManagement.HttpApi.csproj" />
<ProjectReference Include="..\..\..\modules\platform\LINGYUN.Platform.Application\LINGYUN.Platform.Application.csproj" />
<ProjectReference Include="..\..\..\modules\platform\LINGYUN.Platform.EntityFrameworkCore\LINGYUN.Platform.EntityFrameworkCore.csproj" />

66
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/TenantConfigurationProvider.cs

@ -0,0 +1,66 @@
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Platform
{
[Dependency(Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(ITenantConfigurationProvider))]
public class TenantConfigurationProvider : ITenantConfigurationProvider
{
protected virtual ITenantResolver TenantResolver { get; }
protected virtual ITenantStore TenantStore { get; }
protected virtual ITenantResolveResultAccessor TenantResolveResultAccessor { get; }
public TenantConfigurationProvider(
ITenantResolver tenantResolver,
ITenantStore tenantStore,
ITenantResolveResultAccessor tenantResolveResultAccessor)
{
TenantResolver = tenantResolver;
TenantStore = tenantStore;
TenantResolveResultAccessor = tenantResolveResultAccessor;
}
public virtual async Task<TenantConfiguration> GetAsync(bool saveResolveResult = false)
{
var resolveResult = await TenantResolver.ResolveTenantIdOrNameAsync();
if (saveResolveResult)
{
TenantResolveResultAccessor.Result = resolveResult;
}
TenantConfiguration tenant = null;
if (resolveResult.TenantIdOrName != null)
{
tenant = await FindTenantAsync(resolveResult.TenantIdOrName);
if (tenant == null)
{
throw new BusinessException(
code: "Volo.AbpIo.MultiTenancy:010001",
message: "Tenant not found!",
details: "There is no tenant with the tenant id or name: " + resolveResult.TenantIdOrName
);
}
}
return tenant;
}
protected virtual async Task<TenantConfiguration> FindTenantAsync(string tenantIdOrName)
{
if (Guid.TryParse(tenantIdOrName, out var parsedTenantId))
{
return await TenantStore.FindAsync(parsedTenantId);
}
else
{
return await TenantStore.FindAsync(tenantIdOrName);
}
}
}
}

48
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/TenantResolver.cs

@ -0,0 +1,48 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Platform
{
[Dependency(Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(ITenantResolver))]
public class TenantResolver : ITenantResolver
{
private readonly IServiceProvider _serviceProvider;
private readonly AbpTenantResolveOptions _options;
public TenantResolver(IOptions<AbpTenantResolveOptions> options, IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_options = options.Value;
}
public virtual async Task<TenantResolveResult> ResolveTenantIdOrNameAsync()
{
var result = new TenantResolveResult();
using (var serviceScope = _serviceProvider.CreateScope())
{
var context = new TenantResolveContext(serviceScope.ServiceProvider);
foreach (var tenantResolver in _options.TenantResolvers)
{
await tenantResolver.ResolveAsync(context);
result.AppliedResolvers.Add(tenantResolver.Name);
if (context.Handled || context.TenantIdOrName != null)
{
result.TenantIdOrName = context.TenantIdOrName;
break;
}
}
}
return result;
}
}
}

129
vueJs/src/api/oss-manager.ts

@ -0,0 +1,129 @@
import ApiService from './serviceBase'
import { PagedAndSortedResultRequestDto } from './types'
import { urlStringify } from '@/utils/index'
const serviceUrl = process.env.VUE_APP_BASE_API
const containerUrl = '/api/file-management/containes'
const objectUrl = '/api/file-management/objects'
export const objectUploadUrl = objectUrl + '/upload'
export const staticUrl = '/api/files/static/'
export default class OssManager {
public static createBucket(name: string) {
const _url = containerUrl + '/' + name
return ApiService.Post<OssContainer>(_url, null, serviceUrl)
}
public static getBucket(name: string) {
const _url = containerUrl + '/' + name
return ApiService.Get<OssContainer>(_url, serviceUrl)
}
public static getBuckets(input: GetOssContainerRequest) {
const _url = containerUrl + '?' + urlStringify(input)
return ApiService.Get<OssContainerResultList>(_url, serviceUrl)
}
public static deleteBucket(name: string) {
const _url = containerUrl + '/' + name
return ApiService.Delete(_url, serviceUrl)
}
public static createFolder(bucket: string, name: string, path: string = "") {
const input = {
bucket: bucket,
object: name,
path: path
}
return ApiService.Post<OssObject>(objectUrl, input, serviceUrl)
}
public static getObjects(input: GetOssObjectRequest) {
const _url = containerUrl + '/objects?' + urlStringify(input)
return ApiService.Get<OssObjectResultList>(_url, serviceUrl)
}
public static getObject(bucket: string, object: string, path: string = "") {
let _url = objectUrl + '?bucket=' + bucket + '&object=' + object
if (path) {
_url += '&path=' + path
}
return ApiService.Get<OssObject>(_url, serviceUrl)
}
public static getObjectData(bucket: string, object: string, path: string = "") {
let _url = staticUrl + bucket + '/'
if (path) {
// 某些情况下要对 / 编码
_url += '/p/' + path.replace('/', '%2F')
if (_url.endsWith('%2F')) {
_url = _url.substring(0, _url.length - 3) + '/'
}
}
_url += object
return ApiService.HttpRequest<Blob>({
url: _url,
baseURL: serviceUrl,
method: 'GET',
responseType: 'blob'
})
}
public static deleteObject(bucket: string, object: string, path: string = "") {
let _url = objectUrl + '?bucket=' + bucket + '&object=' + object
if (path) {
_url += '&path=' + path
}
return ApiService.Delete(_url, serviceUrl)
}
}
export class GetOssContainerRequest extends PagedAndSortedResultRequestDto {
prefix?: string
marker?: string
}
export class GetOssObjectRequest extends PagedAndSortedResultRequestDto {
bucket!: string
prefix?: string
delimiter?: string = '/'
marker?: string
encodingType?: string
maxResultCount = 100
}
export class OssContainer {
name!: string
size!: number
creationDate?: Date
lastModifiedDate?: Date
metadata?: {[key: string]: string}
}
export class OssContainerResultList {
prefix?: string
marker?: string
nextMarker?: string
maxKeys?: number
containers!: OssContainer[]
}
export class OssObject {
name!: string
path?: string
size!: number
isFolder!: boolean
creationDate?: Date
lastModifiedDate?: Date
metadata?: {[key: string]: string}
}
export class OssObjectResultList {
bucket!: string
prefix?: string
delimiter?: string
marker?: string
nextMarker?: string
maxKeys?: number
objects!: OssObject[]
}

17
vueJs/src/directives/el-table-lazy-load/index.ts

@ -0,0 +1,17 @@
import { DirectiveOptions } from 'vue'
export const elTableLazyLoad: DirectiveOptions = {
inserted(el, binding) {
const selectWrap = el.querySelector('.el-table__body-wrapper')
if (selectWrap) {
selectWrap.addEventListener('scroll', function() {
console.log('onscroll directive')
let sign = 0
const scrollDistance = selectWrap.scrollHeight - selectWrap.scrollTop - selectWrap.clientHeight
if (scrollDistance <= sign) {
binding.value()
}
})
}
}
}

1
vueJs/src/directives/index.ts

@ -1,4 +1,5 @@
export * from './clipboard'
export * from './el-draggable-dialog'
export * from './el-table-lazy-load'
export * from './permission'
export * from './waves'

162
vueJs/src/views/oss-management/components/OssObjectProfile.vue

@ -0,0 +1,162 @@
<template>
<el-dialog
width="800px"
title="Oss对象"
:visible="showDialog"
custom-class="modal-form"
@close="onFormClosed"
>
<div class="app-container">
<el-form
ref="formOssObject"
label-width="130px"
>
<el-form-item label-width="0px">
<el-carousel
:interval="5000"
arrow="always"
class="oss-preview-div"
>
<el-carousel-item>
<el-image
:src="ossPreviewUrl"
fit="contain"
class="oss-preview-img"
>
<div
slot="error"
class="image-slot"
>
<el-alert
title="当前格式不支持预览"
type="warning"
center
show-icon
/>
</div>
</el-image>
</el-carousel-item>
</el-carousel>
</el-form-item>
<el-form-item
label="名称"
>
<el-input
:value="oss.name"
readonly
/>
</el-form-item>
<el-form-item
label="路径"
>
<el-input
:value="oss.path"
readonly
/>
</el-form-item>
<el-form-item
label="大小"
>
<el-input
:value="oss.size"
readonly
/>
</el-form-item>
<el-form-item
label="创建时间"
>
<el-input
:value="oss.creationDate | dateTimeFilter"
readonly
/>
</el-form-item>
</el-form>
</div>
</el-dialog>
</template>
<script lang="ts">
import { Component, Prop, Watch, Vue } from 'vue-property-decorator'
import { dateFormat } from '@/utils/index'
import OssManagerApi, { OssObject } from '@/api/oss-manager'
//
const supportFileTypes = ['jpg', 'png', 'gif', 'bmp', 'jpeg']
@Component({
name: 'OssObjectProfile',
filters: {
dateTimeFilter(datetime: string) {
if (datetime) {
const date = new Date(datetime)
return dateFormat(date, 'YYYY-mm-dd HH:MM:SS')
}
return ''
}
}
})
export default class OssObjectProfile extends Vue {
@Prop({ default: '' })
private name!: string
@Prop({ default: '' })
private bucket!: string
@Prop({ default: '' })
private path?: string
@Prop({ default: false })
private showDialog!: string
private notSupport = false
private ossPreviewUrl = ''
private oss = new OssObject()
@Watch('showDialog', { immediate: true })
private onShowDialogChanged() {
this.handleGetOssObject()
}
private handleGetOssObject() {
if (this.name && this.showDialog) {
this.ossPreviewUrl = ''
OssManagerApi
.getObject(this.bucket, this.name, this.path)
.then(res => {
this.oss = res
this.handleGetOssObjectBase64()
})
}
}
private handleGetOssObjectBase64() {
if (this.oss.name &&
supportFileTypes.some(x => this.oss.name.toLowerCase().endsWith(x))) { //
OssManagerApi
.getObjectData(this.bucket, this.oss.name, this.oss.path)
.then(res => {
const reader = new FileReader()
reader.onload = (e) => {
if (e.target?.result) {
this.ossPreviewUrl = e.target.result.toString()
}
}
reader.readAsDataURL(res)
})
}
}
private onFormClosed() {
this.ossPreviewUrl = ''
this.oss = new OssObject()
this.$emit('closed')
}
}
</script>
<style scoped>
.oss-preview-img {
width: 100%;
height: 100%;
}
</style>

476
vueJs/src/views/oss-management/index.vue

@ -0,0 +1,476 @@
<template>
<div class="app-container">
<div class="filter-container">
<div class="fs-filter">
<el-select
v-model="bucket"
class="fs-bucket"
@change="onBucketChanged"
>
<el-option
v-for="b in buckets"
:key="b.name"
:label="b.name"
:value="b.name"
/>
</el-select>
<el-breadcrumb
ref="fileSystemBreadCrumb"
separator-class="el-icon-arrow-right"
class="fs-breadcrumb"
>
<el-breadcrumb-item
v-for="(fileRoot, index) in fileSystemRoot"
:key="index"
class="file-system-breadcrumb"
@click.native="(event) => onBreadCrumbClick(event, index)"
>
{{ fileRoot }}
</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
<el-table
id="ossObjectTable"
ref="ossObjectTable"
v-loading="objectLoading"
v-el-table-lazy-load="handleGetObjects"
row-key="name"
:data="objects"
border
fit
highlight-current-row
style="width: 100%;"
height="800"
@row-click="onRowClick"
@row-dblclick="onRowDoubleClick"
@contextmenu.native="onContextMenu"
>
<el-table-column
type="selection"
width="50"
align="center"
/>
<el-table-column
:label="$t('fileSystem.name')"
prop="name"
sortable
width="350"
align="left"
>
<template slot-scope="{row}">
<svg-icon
v-if="row.isFolder"
name="folder"
class="folder-icon"
/>
<svg-icon
v-else
name="file"
class="file-icon"
/>
<span>{{ row.name }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('fileSystem.creationTime')"
prop="creationDate"
sortable
width="200"
align="center"
>
<template slot-scope="{row}">
<span>{{ row.creationDate | dateTimeFilter }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('fileSystem.lastModificationTime')"
prop="lastModifiedDate"
sortable
width="200"
align="center"
>
<template slot-scope="{row}">
<span>{{ row.lastModifiedDate | dateTimeFilter }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('fileSystem.type')"
prop="type"
sortable
width="150"
align="center"
>
<template slot-scope="{row}">
<span>{{ row.isFolder ? $t('fileSystem.folder') : '标准存储' }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('fileSystem.size')"
prop="size"
sortable
width="200"
align="center"
>
<template slot-scope="{row}">
<span>{{ row.size | fileSystemSizeFilter }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('global.operaActions')"
align="center"
width="200"
min-width="200"
>
<template slot-scope="{row}">
<el-button
v-permission="['AbpFileManagement.FileSystem.FileManager']"
size="mini"
type="success"
icon="el-icon-tickets"
@click="handleShowOssObject(row)"
/>
<el-button
v-permission="[row.isFolder ? 'AbpFileManagement.FileSystem.Delete' : 'AbpFileManagement.FileSystem.FileManager.Delete']"
size="mini"
type="danger"
icon="el-icon-delete"
@click="handleDeleteOssObject(row)"
/>
<el-button
v-permission="['AbpFileManagement.FileSystem.FileManager.Download']"
:disabled="row.isFolder"
size="mini"
type="info"
icon="el-icon-download"
@click="handleDownloadOssObject(row)"
/>
</template>
</el-table-column>
</el-table>
<OssObjectProfile
:show-dialog="showOssObject"
:bucket="bucket"
:name="selectionOssObject.name"
:path="selectionOssObject.path"
@closed="showOssObject=false"
/>
</div>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import OssManagerApi, {
GetOssContainerRequest,
GetOssObjectRequest,
OssContainer,
OssObject
} from '@/api/oss-manager'
import { dateFormat } from '@/utils/index'
import { checkPermission } from '@/utils/permission'
import OssObjectProfile from './components/OssObjectProfile.vue'
const kbUnit = 1 * 1024
const mbUnit = kbUnit * 1024
const gbUnit = mbUnit * 1024
const $contextmenu = Vue.prototype.$contextmenu
@Component({
name: 'OssManagement',
components: {
OssObjectProfile
},
methods: {
checkPermission
},
filters: {
dateTimeFilter(datetime: string) {
if (!datetime) {
return ''
}
const date = new Date(datetime)
return dateFormat(date, 'YYYY-mm-dd HH:MM')
},
fileSystemSizeFilter(size: number) {
if (size > gbUnit) {
let gb = Math.round(size / gbUnit)
if (gb < 1) {
gb = 1
}
return gb + ' GB'
}
if (size > mbUnit) {
let mb = Math.round(size / mbUnit)
if (mb < 1) {
mb = 1
}
return mb + ' MB'
}
let kb = Math.round(size / kbUnit)
if (kb < 1) {
kb = 1
}
return kb + ' KB'
}
}
})
export default class OssManagement extends Vue {
private bucket = ''
private ossObjectEnd = false
private objectLoading = false
private showOssObject = false
private selectionOssObject = new OssObject()
private buckets = new Array<OssContainer>()
private objects = new Array<OssObject>()
private fileSystemRoot = new Array<string>()
private getObjectRequest = new GetOssObjectRequest()
private getBucketRequest = new GetOssContainerRequest()
mounted() {
this.fileSystemRoot.push(this.$t('fileSystem.root').toString())
this.handleGetBuckets()
}
private navigationToFilePath() {
const fileSystemPathArray = this.fileSystemRoot.slice(1)
const fileSystemPath = fileSystemPathArray.join('')
this.getObjectRequest.prefix = fileSystemPath
this.handleClearObjects()
this.handleGetObjects()
}
private handleGoToLastFolder() {
if (this.fileSystemRoot.length > 1) {
this.fileSystemRoot.splice(this.fileSystemRoot.length - 1)
this.navigationToFilePath()
}
}
private onRowClick(row: any) {
const table = this.$refs.ossObjectTable as any
table.toggleRowSelection(row)
}
private onRowDoubleClick(row: OssObject) {
if (row.isFolder) {
// if (row.name.length > 1 && row.name.endsWith('/')) {
// this.fileSystemRoot.push(row.name.substring(0, row.name.length - 1))
// } else {
// this.fileSystemRoot.push(row.name)
// }
this.fileSystemRoot.push(row.name)
this.navigationToFilePath()
}
}
private onBreadCrumbClick(event: any, index: number) {
// ,
if ((index + 1) < this.fileSystemRoot.length) {
this.fileSystemRoot.splice(index + 1)
this.navigationToFilePath()
} else {
this.handleClearObjects()
this.handleGetObjects()
}
}
private onBucketChanged(bucket: string) {
this.bucket = bucket
this.handleClearObjects()
this.handleGetObjects()
}
private handleGetBuckets() {
if (this.getBucketRequest.skipCount < this.getBucketRequest.maxResultCount) {
this.handleClearObjects()
this.bucket = ''
OssManagerApi
.getBuckets(this.getBucketRequest)
.then(result => {
this.buckets = result.containers
if (result.containers.length === 0) {
//
this.getBucketRequest.skipCount = this.getBucketRequest.maxResultCount
}
})
}
}
private handleGetObjects() {
if (this.bucket && !this.ossObjectEnd) {
this.objectLoading = true
this.getObjectRequest.bucket = this.bucket
OssManagerApi
.getObjects(this.getObjectRequest)
.then(result => {
this.objects = this.objects.concat(result.objects)
this.getObjectRequest.prefix = result.prefix ?? ''
this.getObjectRequest.delimiter = result.delimiter ?? ''
this.getObjectRequest.marker = result.nextMarker ?? ''
if (!result.nextMarker || result.objects.length === 0) {
this.ossObjectEnd = true
}
})
.finally(() => {
this.objectLoading = false
})
}
}
private handleDeleteOssObject(oss: OssObject) {
this.$confirm(this.l('global.whetherDeleteData', { name: oss.name }),
this.l('global.questingDeleteByMessage',
{ message: oss.isFolder ? this.l('fileSystem.folder') : this.l('fileSystem.file') }), {
callback: (action) => {
if (action === 'confirm') {
OssManagerApi
.deleteObject(this.bucket, oss.name, oss.path)
.then(() => {
this.$notify.success(this.l('global.dataHasBeenDeleted', { name: oss.name }))
this.handleGetObjects()
})
}
}
})
}
private handleShowOssObject(oss: OssObject) {
this.selectionOssObject = oss
this.showOssObject = true
}
private handleDownloadOssObject(oss: OssObject) {
console.log(oss)
}
private handleFileSystemCommand(command: any) {
console.log(command)
}
private handleClearObjects() {
this.objects.length = 0
this.ossObjectEnd = false
this.objectLoading = false
}
private onContextMenu(event: any) {
event.preventDefault()
$contextmenu({
items: [
{
label: this.$t('fileSystem.addFolder'),
disabled: !checkPermission(['AbpFileManagement.FileSystem.Create']),
onClick: () => {
let parent = ''
//
if (this.fileSystemRoot.length > 1) {
parent = this.fileSystemRoot.slice(1).join('')
}
this.$prompt(this.$t('global.pleaseInputBy', { key: this.$t('fileSystem.name') }).toString(),
this.$t('fileSystem.addFolder').toString(), {
showInput: true,
inputValidator: (val) => {
return !(!val || val.length === 0)
},
inputErrorMessage: this.$t('fileSystem.folderNameIsRequired').toString(),
inputPlaceholder: this.$t('global.pleaseInputBy', { key: this.$t('fileSystem.name') }).toString()
}).then((val: any) => {
const name = val.value + '/'
OssManagerApi
.createFolder(this.bucket, name.replace('//', '/'), parent)
.then(res => {
this.$message.success(this.$t('fileSystem.folderCreateSuccess', { name: res.name }).toString())
this.handleClearObjects()
this.handleGetObjects()
})
}).catch(_ => _)
},
divided: true
},
{
label: this.$t('fileSystem.upload'),
disabled: !checkPermission(['AbpFileManagement.FileSystem.FileManager.Create']),
onClick: () => {
let path = ''
if (this.fileSystemRoot.length > 1) {
path = this.fileSystemRoot.slice(1).join('/')
}
},
divided: true
},
{
label: this.$t('fileSystem.bacthDownload'),
disabled: !checkPermission(['AbpFileManagement.FileSystem.FileManager.Download']),
onClick: () => {
const table = this.$refs.ossObjectTable as any
}
},
{
label: this.$t('fileSystem.bacthDelete'),
disabled: true, // !checkPermission(['AbpFileManagement.FileSystem.FileManager.Delete']),
onClick: () => {
//
// const table = this.$refs.ossObjectTable as any
//
// const selectFiles = table.selection.filter((x: any) => x.type === 1)
}
}
],
event,
customClass: 'context-menu',
zIndex: 3,
minWidth: 150
})
return false
}
private l(name: string, values?: any[] | { [key: string]: any }) {
return this.$t(name, values).toString()
}
}
</script>
<style lang="scss">
.el-table .folder-row {
cursor: pointer;
background-color:rgb(245, 235, 226);
}
.el-table .file-row {
cursor: pointer;
background-color: rgb(210, 219, 235);
}
.fs-filter {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: stretch;
.fs-bucket {
width: 300px;
}
.fs-breadcrumb {
padding-left: 10px;
padding-top: 10px;
}
}
.file-system-breadcrumb .el-breadcrumb__inner {
color: rgb(34, 34, 173);
cursor: pointer;
}
.file-icon {
margin-left: 0px;
margin-right: 5px;
margin-top: 0px;
margin-bottom: 0px;
color: rgb(55, 189, 189);
}
.folder-icon {
margin-left: 0px;
margin-right: 5px;
margin-top: 0px;
margin-bottom: 0px;
color: rgb(235, 130, 33);
}
</style>
Loading…
Cancel
Save