diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetPublicFileInput.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetPublicFileInput.cs new file mode 100644 index 000000000..df15796ed --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/GetPublicFileInput.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.Abp.OssManagement +{ + public class GetPublicFileInput + { + [Required] + public string Name { get; set; } + + public string Path { get; set; } + + public string Process { get; set; } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IFileAppService.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IFileAppService.cs new file mode 100644 index 000000000..fe44d9d9c --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IFileAppService.cs @@ -0,0 +1,13 @@ +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.OssManagement +{ + public interface IFileAppService : IApplicationService + { + Task UploadAsync(UploadPublicFileInput input); + + Task GetAsync(GetPublicFileInput input); + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IFileValidater.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IFileValidater.cs new file mode 100644 index 000000000..08de884c8 --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IFileValidater.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.OssManagement +{ + public interface IFileValidater + { + Task ValidationAsync(UploadFile input); + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IPrivateFileAppService.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IPrivateFileAppService.cs new file mode 100644 index 000000000..6487dde80 --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IPrivateFileAppService.cs @@ -0,0 +1,6 @@ +namespace LINGYUN.Abp.OssManagement +{ + public interface IPrivateFileAppService : IFileAppService + { + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IPublicFileAppService.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IPublicFileAppService.cs new file mode 100644 index 000000000..6f3a8c4b6 --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/IPublicFileAppService.cs @@ -0,0 +1,6 @@ +namespace LINGYUN.Abp.OssManagement +{ + public interface IPublicFileAppService : IFileAppService + { + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/UploadFile.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/UploadFile.cs new file mode 100644 index 000000000..ac0988760 --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/UploadFile.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.Abp.OssManagement +{ + public class UploadFile + { + /// + /// 总文件大小 + /// + [Required] + public long TotalSize { get; set; } + /// + /// 文件名 + /// + [Required] + public string FileName { get; set; } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/UploadPublicFileInput.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/UploadPublicFileInput.cs new file mode 100644 index 000000000..6eb52a8bb --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/UploadPublicFileInput.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using System.IO; +using Volo.Abp.Auditing; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.OssManagement +{ + public class UploadPublicFileInput + { + public string Path { get; set; } + public string Object { get; set; } + public bool Overwrite { get; set; } = true; + + [Required] + [DisableAuditing] + [DisableValidation] + public Stream Content { get; set; } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileAppServiceBase.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileAppServiceBase.cs new file mode 100644 index 000000000..6ca0f744f --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/FileAppServiceBase.cs @@ -0,0 +1,84 @@ +using LINGYUN.Abp.Features.LimitValidation; +using LINGYUN.Abp.OssManagement.Features; +using System; +using System.IO; +using System.Threading.Tasks; +using System.Web; +using Volo.Abp.Features; + +namespace LINGYUN.Abp.OssManagement +{ + public abstract class FileAppServiceBase : OssManagementApplicationServiceBase, IFileAppService + { + private readonly IFileValidater _fileValidater; + private readonly IOssContainerFactory _ossContainerFactory; + + protected FileAppServiceBase( + IFileValidater fileValidater, + IOssContainerFactory ossContainerFactory) + { + _fileValidater = fileValidater; + _ossContainerFactory = ossContainerFactory; + } + + [RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)] + [RequiresLimitFeature( + AbpOssManagementFeatureNames.OssObject.UploadLimit, + AbpOssManagementFeatureNames.OssObject.UploadInterval, + LimitPolicy.Month)] + public virtual async Task UploadAsync(UploadPublicFileInput input) + { + await _fileValidater.ValidationAsync(new UploadFile + { + TotalSize = input.Content.Length, + FileName = input.Object + }); + + var oss = _ossContainerFactory.Create(); + + var createOssObjectRequest = new CreateOssObjectRequest( + GetCurrentBucket(), + HttpUtility.UrlDecode(input.Object), + input.Content, + GetCurrentPath(HttpUtility.UrlDecode(input.Path))) + { + Overwrite = input.Overwrite + }; + + var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); + + return ObjectMapper.Map(ossObject); + } + + [RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)] + [RequiresLimitFeature( + AbpOssManagementFeatureNames.OssObject.DownloadLimit, + AbpOssManagementFeatureNames.OssObject.DownloadInterval, + LimitPolicy.Month)] + public virtual async Task GetAsync(GetPublicFileInput input) + { + var ossObjectRequest = new GetOssObjectRequest( + GetCurrentBucket(), + // 需要处理特殊字符 + HttpUtility.UrlDecode(input.Name), + GetCurrentPath(HttpUtility.UrlDecode(input.Path)), + HttpUtility.UrlDecode(input.Process)); + + var ossContainer = _ossContainerFactory.Create(); + var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest); + + return ossObject.Content; + } + + protected virtual string GetCurrentBucket() + { + throw new System.NotImplementedException(); + } + + protected virtual string GetCurrentPath(string path) + { + path = path.RemovePreFix(".").RemovePreFix("/"); + return path; + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PrivateFileAppService.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PrivateFileAppService.cs new file mode 100644 index 000000000..0ea4227ba --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PrivateFileAppService.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Authorization; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.OssManagement +{ + /// + /// 所有登录用户访问私有文件服务接口 + /// bucket限制在users + /// path限制在用户id + /// + [Authorize] + // 不对外公开,仅通过控制器调用 + //[RemoteService(IsMetadataEnabled = false)] + public class PrivateFileAppService : FileAppServiceBase, IPrivateFileAppService + { + public PrivateFileAppService( + IFileValidater fileValidater, + IOssContainerFactory ossContainerFactory) + : base(fileValidater, ossContainerFactory) + { + } + protected override string GetCurrentBucket() + { + return "users"; + } + + protected override string GetCurrentPath(string path) + { + path = base.GetCurrentPath(path); + var userId = CurrentUser.GetId().ToString("N"); + return path.StartsWith(userId) ? path : $"{userId}/{path}"; + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementOptions.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementOptions.cs new file mode 100644 index 000000000..38cdefd93 --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementOptions.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Linq; +using Volo.Abp; + +namespace LINGYUN.Abp.OssManagement +{ + public class AbpOssManagementOptions + { + /// + /// 静态容器 + /// 不允许被删除 + /// + public List StaticBuckets { get; } + + public AbpOssManagementOptions() + { + StaticBuckets = new List + { + "public", + "users", + "system", + }; + } + + public void AddStaticBucket(string bucket) + { + Check.NotNullOrWhiteSpace(bucket, nameof(bucket)); + + StaticBuckets.AddIfNotContains(bucket); + } + + public bool CheckStaticBucket(string bucket) + { + return StaticBuckets.Any(bck => bck.Equals(bucket)); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PrivateFilesController.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PrivateFilesController.cs new file mode 100644 index 000000000..3466ee0ac --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PrivateFilesController.cs @@ -0,0 +1,89 @@ +using LINGYUN.Abp.OssManagement.Localization; +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.OssManagement +{ + [Area("oss-management")] + [Route("api/files/private")] + [RemoteService(false)] + [ApiExplorerSettings(IgnoreApi = true)] + public class PrivateFilesController : AbpController + { + private readonly IPrivateFileAppService _privateFileAppService; + + public PrivateFilesController( + IPrivateFileAppService privateFileAppService) + { + _privateFileAppService = privateFileAppService; + + LocalizationResource = typeof(AbpOssManagementResource); + } + + [HttpPost] + [Route("{path}")] + [Route("{path}/{name}")] + public virtual async Task UploadAsync(string path, string name) + { + if (Request.ContentLength <= 0) + { + ThrowValidationException(L["FileNotBeNullOrEmpty"], "File"); + } + + var file = Request.Form.Files[0]; + var fileName = name ?? file.FileName; + + var createOssObjectInput = new UploadPublicFileInput + { + Path = path, + Object = fileName, + Content = file.OpenReadStream(), + Overwrite = true + }; + + return await _privateFileAppService.UploadAsync(createOssObjectInput); + } + + [HttpGet] + [Route("{name}")] + [Route("{name}/{process}")] + [Route("p/{path}/{name}")] + [Route("p/{path}/{name}/{process}")] + public virtual async Task GetAsync(string path, string name, string process) + { + var input = new GetPublicFileInput + { + Name = name, + Path = path, + Process = process + }; + var fileStream = await _privateFileAppService.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 + { + new ValidationResult(message, new[] {memberName}) + }); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PublicFilesController.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PublicFilesController.cs new file mode 100644 index 000000000..4c0e4ce0c --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/PublicFilesController.cs @@ -0,0 +1,89 @@ +using LINGYUN.Abp.OssManagement.Localization; +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.OssManagement +{ + [Area("oss-management")] + [Route("api/files/public")] + [RemoteService(false)] + [ApiExplorerSettings(IgnoreApi = true)] + public class PublicFilesController : AbpController + { + private readonly IPublicFileAppService _publicFileAppService; + + public PublicFilesController( + IPublicFileAppService publicFileAppService) + { + _publicFileAppService = publicFileAppService; + + LocalizationResource = typeof(AbpOssManagementResource); + } + + [HttpPost] + [Route("{path}")] + [Route("{path}/{name}")] + public virtual async Task UploadAsync(string path, string name) + { + if (Request.ContentLength <= 0) + { + ThrowValidationException(L["FileNotBeNullOrEmpty"], "File"); + } + + var file = Request.Form.Files[0]; + var fileName = name ?? file.FileName; + + var createOssObjectInput = new UploadPublicFileInput + { + Path = path, + Object = fileName, + Content = file.OpenReadStream(), + Overwrite = true + }; + + return await _publicFileAppService.UploadAsync(createOssObjectInput); + } + + [HttpGet] + [Route("{name}")] + [Route("{name}/{process}")] + [Route("p/{path}/{name}")] + [Route("p/{path}/{name}/{process}")] + public virtual async Task GetAsync(string path, string name, string process) + { + var input = new GetPublicFileInput + { + Name = name, + Path = path, + Process = process + }; + var fileStream = await _publicFileAppService.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 + { + new ValidationResult(message, new[] {memberName}) + }); + } + } +} diff --git a/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/LINGYUN/Abp/OssManagement/SettingManagement/AbpOssManagementSettingManagementModule.cs b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/LINGYUN/Abp/OssManagement/SettingManagement/AbpOssManagementSettingManagementModule.cs new file mode 100644 index 000000000..9e120094b --- /dev/null +++ b/aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/LINGYUN/Abp/OssManagement/SettingManagement/AbpOssManagementSettingManagementModule.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.OssManagement.SettingManagement +{ + [DependsOn( + typeof(AbpOssManagementApplicationContractsModule), + typeof(AbpAspNetCoreMvcModule))] + public class AbpOssManagementSettingManagementModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementSettingManagementModule).Assembly); + }); + } + } +}