14 changed files with 530 additions and 241 deletions
@ -1,13 +1,18 @@ |
|||
using Volo.Abp.EventBus; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpEventBusModule), |
|||
typeof(AbpLocalizationModule))] |
|||
public class AbpLocalizationDynamicModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.EventBus; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpEventBusModule), |
|||
typeof(AbpLocalizationModule))] |
|||
public class AbpLocalizationDynamicModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddHostedService<DynamicLocalizationInitializeService>(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,22 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class AbpLocalizationDynamicOptions |
|||
{ |
|||
internal LocalizationDictionary LocalizationDictionary { get; } |
|||
|
|||
public AbpLocalizationDynamicOptions() |
|||
{ |
|||
LocalizationDictionary = new LocalizationDictionary(); |
|||
} |
|||
|
|||
internal void AddOrUpdate(string resourceName, Dictionary<string, ILocalizationDictionary> dictionares) |
|||
{ |
|||
var _dictionares = LocalizationDictionary |
|||
.GetOrAdd(resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
|||
_dictionares.AddIfNotContains(dictionares); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using Microsoft.Extensions.Hosting; |
|||
using Microsoft.Extensions.Options; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class DynamicLocalizationInitializeService : IHostedService |
|||
{ |
|||
protected ILocalizationStore Store { get; } |
|||
protected AbpLocalizationOptions LocalizationOptions { get; } |
|||
protected AbpLocalizationDynamicOptions DynamicOptions { get; } |
|||
|
|||
public DynamicLocalizationInitializeService( |
|||
ILocalizationStore store, |
|||
IOptions<AbpLocalizationOptions> localizationOptions, |
|||
IOptions<AbpLocalizationDynamicOptions> dynamicOptions) |
|||
{ |
|||
Store = store; |
|||
DynamicOptions = dynamicOptions.Value; |
|||
LocalizationOptions = localizationOptions.Value; |
|||
} |
|||
|
|||
public virtual async Task StartAsync(CancellationToken cancellationToken) |
|||
{ |
|||
foreach (var resource in LocalizationOptions.Resources) |
|||
{ |
|||
foreach (var contributor in resource.Value.Contributors) |
|||
{ |
|||
if (contributor.GetType().IsAssignableFrom(typeof(DynamicLocalizationResourceContributor))) |
|||
{ |
|||
var resourceLocalizationDic = await Store.GetLocalizationDictionaryAsync(resource.Value.ResourceName); |
|||
DynamicOptions.AddOrUpdate(resource.Value.ResourceName, resourceLocalizationDic); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public Task StopAsync(CancellationToken cancellationToken) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -1,120 +1,41 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Nito.AsyncEx; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class DynamicLocalizationResourceContributor : ILocalizationResourceContributor |
|||
{ |
|||
private ILogger _logger; |
|||
private ILocalizationSubscriber _subscriber; |
|||
|
|||
private ILocalizationStore _store; |
|||
protected ILocalizationStore Store => _store; |
|||
|
|||
private Dictionary<string, ILocalizationDictionary> _dictionaries; |
|||
|
|||
private readonly string _resourceName; |
|||
private readonly AsyncLock _asyncLock = new AsyncLock(); |
|||
|
|||
public DynamicLocalizationResourceContributor(string resourceName) |
|||
{ |
|||
_resourceName = resourceName; |
|||
} |
|||
|
|||
public virtual void Initialize(LocalizationResourceInitializationContext context) |
|||
{ |
|||
_logger = context.ServiceProvider.GetService<ILogger<DynamicLocalizationResourceContributor>>(); |
|||
|
|||
_store = context.ServiceProvider.GetRequiredService<ILocalizationStore>(); |
|||
_subscriber = context.ServiceProvider.GetRequiredService<ILocalizationSubscriber>(); |
|||
_subscriber.Subscribe(OnChanged); |
|||
} |
|||
|
|||
public virtual void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary) |
|||
{ |
|||
GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); |
|||
} |
|||
|
|||
public virtual LocalizedString GetOrNull(string cultureName, string name) |
|||
{ |
|||
return GetDictionaries().GetOrDefault(cultureName)?.GetOrNull(name); |
|||
} |
|||
|
|||
protected virtual Dictionary<string, ILocalizationDictionary> GetDictionaries() |
|||
{ |
|||
var dictionaries = _dictionaries; |
|||
if (dictionaries != null) |
|||
{ |
|||
return dictionaries; |
|||
} |
|||
|
|||
try |
|||
{ |
|||
using (_asyncLock.Lock()) |
|||
{ |
|||
dictionaries = _dictionaries = AsyncHelper.RunSync(async () => |
|||
await Store.GetLocalizationDictionaryAsync(_resourceName)); |
|||
} |
|||
} |
|||
catch(Exception ex) |
|||
{ |
|||
// 错误不应该影响到应用程序,而是记录到日志
|
|||
_logger?.LogWarning("Failed to get localized text, error: ", ex.Message); |
|||
} |
|||
|
|||
return dictionaries; |
|||
} |
|||
|
|||
private Task OnChanged(LocalizedStringCacheResetEventData data) |
|||
{ |
|||
if (string.Equals(_resourceName, data.ResourceName)) |
|||
{ |
|||
if (!_dictionaries.ContainsKey(data.CultureName)) |
|||
{ |
|||
// TODO: 需要处理 data.Key data.Value 空引用
|
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
dictionary.Add(data.Key, new LocalizedString(data.Key, data.Value.NormalizeLineEndings())); |
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(data.CultureName, dictionary); |
|||
|
|||
_dictionaries.Add(data.CultureName, newLocalizationDictionary); |
|||
} |
|||
else |
|||
{ |
|||
// 取出当前的缓存写入到新字典进行处理
|
|||
var nowLocalizationDictionary = _dictionaries[data.CultureName]; |
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
nowLocalizationDictionary.Fill(dictionary); |
|||
|
|||
var existsKey = dictionary.ContainsKey(data.Key); |
|||
if (!existsKey) |
|||
{ |
|||
// 如果不存在,则新增
|
|||
dictionary.Add(data.Key, new LocalizedString(data.Key, data.Value.NormalizeLineEndings())); |
|||
} |
|||
else if (existsKey && data.IsDeleted) |
|||
{ |
|||
// 如果删掉了本地化的节点,删掉当前的缓存
|
|||
dictionary.Remove(data.Key); |
|||
} |
|||
|
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(data.CultureName, dictionary); |
|||
|
|||
if (newLocalizationDictionary != null) |
|||
{ |
|||
// 重新赋值变更过的缓存
|
|||
_dictionaries[data.CultureName] = newLocalizationDictionary; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Options; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class DynamicLocalizationResourceContributor : ILocalizationResourceContributor |
|||
{ |
|||
private readonly string _resourceName; |
|||
|
|||
private AbpLocalizationDynamicOptions _options; |
|||
|
|||
public DynamicLocalizationResourceContributor(string resourceName) |
|||
{ |
|||
_resourceName = resourceName; |
|||
} |
|||
|
|||
public virtual void Initialize(LocalizationResourceInitializationContext context) |
|||
{ |
|||
_options = context.ServiceProvider.GetService<IOptions<AbpLocalizationDynamicOptions>>().Value; |
|||
} |
|||
|
|||
public virtual void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary) |
|||
{ |
|||
GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); |
|||
} |
|||
|
|||
public virtual LocalizedString GetOrNull(string cultureName, string name) |
|||
{ |
|||
return GetDictionaries().GetOrDefault(cultureName)?.GetOrNull(name); |
|||
} |
|||
|
|||
protected virtual Dictionary<string, ILocalizationDictionary> GetDictionaries() |
|||
{ |
|||
return _options.LocalizationDictionary |
|||
.GetOrAdd(_resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,14 +0,0 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
internal interface ILocalizationDispatcher |
|||
{ |
|||
/// <summary>
|
|||
/// 发布变更事件
|
|||
/// </summary>
|
|||
/// <param name="data"></param>
|
|||
/// <returns></returns>
|
|||
Task DispatchAsync(LocalizedStringCacheResetEventData data); |
|||
} |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
/// <summary>
|
|||
/// 本地化资源订阅
|
|||
/// </summary>
|
|||
internal interface ILocalizationSubscriber |
|||
{ |
|||
/// <summary>
|
|||
/// 订阅变更事件
|
|||
/// </summary>
|
|||
/// <param name="func"></param>
|
|||
void Subscribe(Func<LocalizedStringCacheResetEventData, Task> func); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class LocalizationDictionary : Dictionary<string, Dictionary<string, ILocalizationDictionary>> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -1,23 +1,72 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
internal class LocalizationResetSynchronizer : |
|||
IDistributedEventHandler<LocalizedStringCacheResetEventData>, |
|||
ITransientDependency |
|||
{ |
|||
private readonly ILocalizationDispatcher _dispatcher; |
|||
|
|||
public LocalizationResetSynchronizer( |
|||
ILocalizationDispatcher dispatcher) |
|||
{ |
|||
_dispatcher = dispatcher; |
|||
} |
|||
public async Task HandleEventAsync(LocalizedStringCacheResetEventData eventData) |
|||
{ |
|||
await _dispatcher.DispatchAsync(eventData); |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
internal class LocalizationResetSynchronizer : |
|||
IDistributedEventHandler<LocalizedStringCacheResetEventData>, |
|||
ITransientDependency |
|||
{ |
|||
private readonly AbpLocalizationDynamicOptions _options; |
|||
|
|||
public LocalizationResetSynchronizer( |
|||
IOptions<AbpLocalizationDynamicOptions> options) |
|||
{ |
|||
_options = options.Value; |
|||
} |
|||
public virtual Task HandleEventAsync(LocalizedStringCacheResetEventData eventData) |
|||
{ |
|||
var dictionaries = GetDictionaries(eventData.ResourceName); |
|||
if (!dictionaries.ContainsKey(eventData.CultureName)) |
|||
{ |
|||
// TODO: 需要处理 data.Key data.Value 空引用
|
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
dictionary.Add(eventData.Key, new LocalizedString(eventData.Key, eventData.Value.NormalizeLineEndings())); |
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(eventData.CultureName, dictionary); |
|||
|
|||
dictionaries.Add(eventData.CultureName, newLocalizationDictionary); |
|||
} |
|||
else |
|||
{ |
|||
// 取出当前的缓存写入到新字典进行处理
|
|||
var nowLocalizationDictionary = dictionaries[eventData.CultureName]; |
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
nowLocalizationDictionary.Fill(dictionary); |
|||
|
|||
var existsKey = dictionary.ContainsKey(eventData.Key); |
|||
if (!existsKey) |
|||
{ |
|||
// 如果不存在,则新增
|
|||
dictionary.Add(eventData.Key, new LocalizedString(eventData.Key, eventData.Value.NormalizeLineEndings())); |
|||
} |
|||
else if (existsKey && eventData.IsDeleted) |
|||
{ |
|||
// 如果删掉了本地化的节点,删掉当前的缓存
|
|||
dictionary.Remove(eventData.Key); |
|||
} |
|||
|
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(eventData.CultureName, dictionary); |
|||
|
|||
if (newLocalizationDictionary != null) |
|||
{ |
|||
// 重新赋值变更过的缓存
|
|||
dictionaries[eventData.CultureName] = newLocalizationDictionary; |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual Dictionary<string, ILocalizationDictionary> GetDictionaries(string resourceName) |
|||
{ |
|||
return _options.LocalizationDictionary |
|||
.GetOrAdd(resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,33 +0,0 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
[ExposeServices( |
|||
typeof(ILocalizationSubscriber), |
|||
typeof(ILocalizationDispatcher), |
|||
typeof(LocalizationSubscriber))] |
|||
internal class LocalizationSubscriber : ILocalizationSubscriber, ILocalizationDispatcher, ISingletonDependency |
|||
{ |
|||
private Func<LocalizedStringCacheResetEventData, Task> _handler; |
|||
|
|||
public LocalizationSubscriber() |
|||
{ |
|||
_handler = (d) => |
|||
{ |
|||
return Task.CompletedTask; |
|||
}; |
|||
} |
|||
|
|||
public void Subscribe(Func<LocalizedStringCacheResetEventData, Task> func) |
|||
{ |
|||
_handler += func; |
|||
} |
|||
|
|||
public virtual async Task DispatchAsync(LocalizedStringCacheResetEventData data) |
|||
{ |
|||
await _handler(data); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
using LINGYUN.Abp.OssManagement.Localization; |
|||
using LINGYUN.Abp.OssManagement.Settings; |
|||
using Microsoft.Extensions.Caching.Memory; |
|||
using Microsoft.Extensions.Localization; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.IO; |
|||
using Volo.Abp.Settings; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
public class FileValidater : IFileValidater, ISingletonDependency |
|||
{ |
|||
private readonly IMemoryCache _cache; |
|||
private readonly ISettingProvider _settingProvider; |
|||
private readonly IServiceProvider _serviceProvider; |
|||
private readonly IStringLocalizer _stringLocalizer; |
|||
|
|||
public FileValidater( |
|||
IMemoryCache cache, |
|||
ISettingProvider settingProvider, |
|||
IServiceProvider serviceProvider, |
|||
IStringLocalizer<AbpOssManagementResource> stringLocalizer) |
|||
{ |
|||
_cache = cache; |
|||
_settingProvider = settingProvider; |
|||
_serviceProvider = serviceProvider; |
|||
_stringLocalizer = stringLocalizer; |
|||
} |
|||
|
|||
public virtual async Task ValidationAsync(UploadFile input) |
|||
{ |
|||
var validation = await GetByCacheItemAsync(); |
|||
if (validation.SizeLimit * 1024 * 1024 < input.TotalSize) |
|||
{ |
|||
throw new UserFriendlyException(_stringLocalizer["UploadFileSizeBeyondLimit", validation.SizeLimit]); |
|||
} |
|||
var fileExtensionName = FileHelper.GetExtension(input.FileName); |
|||
if (!validation.AllowedExtensions |
|||
.Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase))) |
|||
{ |
|||
throw new UserFriendlyException(_stringLocalizer["NotAllowedFileExtensionName", fileExtensionName]); |
|||
} |
|||
} |
|||
|
|||
protected virtual async Task<FileValidation> GetByCacheItemAsync() |
|||
{ |
|||
var fileValidation = _cache.Get<FileValidation>(FileValidation.CacheKey); |
|||
if (fileValidation == null) |
|||
{ |
|||
fileValidation = await GetBySettingAsync(); |
|||
_cache.Set(FileValidation.CacheKey, |
|||
fileValidation, |
|||
new MemoryCacheEntryOptions |
|||
{ |
|||
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(2) |
|||
}); |
|||
} |
|||
return fileValidation; |
|||
} |
|||
|
|||
protected virtual async Task<FileValidation> GetBySettingAsync() |
|||
{ |
|||
var fileSizeLimited = await _settingProvider |
|||
.GetAsync( |
|||
AbpOssManagementSettingNames.FileLimitLength, |
|||
AbpOssManagementSettingNames.DefaultFileLimitLength); |
|||
var fileAllowExtension = await _settingProvider |
|||
.GetOrDefaultAsync(AbpOssManagementSettingNames.AllowFileExtensions, _serviceProvider); |
|||
|
|||
return new FileValidation(fileSizeLimited, fileAllowExtension.Split(',')); |
|||
} |
|||
} |
|||
|
|||
public class FileValidation |
|||
{ |
|||
public const string CacheKey = "Abp.OssManagement.FileValidation"; |
|||
public long SizeLimit { get; set; } |
|||
public string[] AllowedExtensions { get; set; } |
|||
public FileValidation() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public FileValidation( |
|||
long sizeLimit, |
|||
string[] allowedExtensions) |
|||
{ |
|||
SizeLimit = sizeLimit; |
|||
AllowedExtensions = allowedExtensions; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
using LINGYUN.Abp.Features.LimitValidation; |
|||
using LINGYUN.Abp.OssManagement.Features; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using System.Web; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Features; |
|||
using Volo.Abp.Users; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement |
|||
{ |
|||
/// <summary>
|
|||
/// 所有登录用户公开访问文件服务接口
|
|||
/// bucket限制在users
|
|||
/// path限制在用户id
|
|||
/// </summary>
|
|||
[Authorize] |
|||
// 不对外公开,仅通过控制器调用
|
|||
[RemoteService(IsEnabled = false, IsMetadataEnabled = false)] |
|||
public class PublicFileAppService : OssManagementApplicationServiceBase, IPublicFileAppService |
|||
{ |
|||
private readonly IFileValidater _fileValidater; |
|||
private readonly IOssContainerFactory _ossContainerFactory; |
|||
|
|||
public PublicFileAppService( |
|||
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<OssObjectDto> UploadAsync(UploadPublicFileInput input) |
|||
{ |
|||
await _fileValidater.ValidationAsync(new UploadFile |
|||
{ |
|||
TotalSize = input.Content.Length, |
|||
FileName = input.Object |
|||
}); |
|||
|
|||
var oss = _ossContainerFactory.Create(); |
|||
|
|||
var createOssObjectRequest = new CreateOssObjectRequest( |
|||
"users", |
|||
HttpUtility.UrlDecode(input.Object), |
|||
input.Content, |
|||
GetCurrentUserPath(HttpUtility.UrlDecode(input.Path))) |
|||
{ |
|||
Overwrite = input.Overwrite |
|||
}; |
|||
|
|||
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest); |
|||
|
|||
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject); |
|||
} |
|||
|
|||
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)] |
|||
[RequiresLimitFeature( |
|||
AbpOssManagementFeatureNames.OssObject.DownloadLimit, |
|||
AbpOssManagementFeatureNames.OssObject.DownloadInterval, |
|||
LimitPolicy.Month)] |
|||
public virtual async Task<Stream> GetAsync(GetPublicFileInput input) |
|||
{ |
|||
var ossObjectRequest = new GetOssObjectRequest( |
|||
"users", // 需要处理特殊字符
|
|||
HttpUtility.UrlDecode(input.Name), |
|||
GetCurrentUserPath(HttpUtility.UrlDecode(input.Path)), |
|||
HttpUtility.UrlDecode(input.Process)); |
|||
|
|||
var ossContainer = _ossContainerFactory.Create(); |
|||
var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest); |
|||
|
|||
return ossObject.Content; |
|||
} |
|||
|
|||
private string GetCurrentUserPath(string path) |
|||
{ |
|||
path = path.StartsWith("/") ? path.Substring(1) : path; |
|||
var userId = CurrentUser.GetId().ToString(); |
|||
return path.StartsWith(userId) ? path : $"{userId}/{path}"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
using LINGYUN.Abp.OssManagement.Localization; |
|||
using Volo.Abp.Features; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Validation.StringValues; |
|||
|
|||
namespace LINGYUN.Abp.OssManagement.Features |
|||
{ |
|||
public class AbpOssManagementFeatureDefinitionProvider : FeatureDefinitionProvider |
|||
{ |
|||
public override void Define(IFeatureDefinitionContext context) |
|||
{ |
|||
var featureGroup = context.AddGroup( |
|||
name: AbpOssManagementFeatureNames.GroupName, |
|||
displayName: L("Features:OssManagement")); |
|||
|
|||
var ossFeature = featureGroup.AddFeature( |
|||
name: AbpOssManagementFeatureNames.OssObject.Default, |
|||
defaultValue: true.ToString(), |
|||
displayName: L("Features:DisplayName:OssObject"), |
|||
description: L("Features:Description:OssObject"), |
|||
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
|||
|
|||
ossFeature.CreateChild( |
|||
name: AbpOssManagementFeatureNames.OssObject.DownloadFile, |
|||
defaultValue: false.ToString(), |
|||
displayName: L("Features:DisplayName:DownloadFile"), |
|||
description: L("Features:Description:DownloadFile"), |
|||
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
|||
ossFeature.CreateChild( |
|||
name: AbpOssManagementFeatureNames.OssObject.DownloadLimit, |
|||
defaultValue: "1000", |
|||
displayName: L("Features:DisplayName:DownloadLimit"), |
|||
description: L("Features:Description:DownloadLimit"), |
|||
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用
|
|||
ossFeature.CreateChild( |
|||
name: AbpOssManagementFeatureNames.OssObject.DownloadInterval, |
|||
defaultValue: "1", |
|||
displayName: L("Features:DisplayName:DownloadInterval"), |
|||
description: L("Features:Description:DownloadInterval"), |
|||
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月
|
|||
|
|||
ossFeature.CreateChild( |
|||
name: AbpOssManagementFeatureNames.OssObject.UploadFile, |
|||
defaultValue: true.ToString(), |
|||
displayName: L("Features:DisplayName:UploadFile"), |
|||
description: L("Features:Description:UploadFile"), |
|||
valueType: new ToggleStringValueType(new BooleanValueValidator())); |
|||
ossFeature.CreateChild( |
|||
name: AbpOssManagementFeatureNames.OssObject.UploadLimit, |
|||
defaultValue: "1000", |
|||
displayName: L("Features:DisplayName:UploadLimit"), |
|||
description: L("Features:Description:UploadLimit"), |
|||
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用
|
|||
ossFeature.CreateChild( |
|||
name: AbpOssManagementFeatureNames.OssObject.UploadInterval, |
|||
defaultValue: "1", |
|||
displayName: L("Features:DisplayName:UploadInterval"), |
|||
description: L("Features:Description:UploadInterval"), |
|||
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月
|
|||
|
|||
// TODO: 此功能需要控制器协同,暂时不实现
|
|||
//fileSystemFeature.CreateChild(
|
|||
// name: AbpOssManagementFeatureNames.OssObject.MaxUploadFileCount,
|
|||
// defaultValue: 1.ToString(),
|
|||
// displayName: L("Features:DisplayName:MaxUploadFileCount"),
|
|||
// description: L("Features:Description:MaxUploadFileCount"),
|
|||
// valueType: new FreeTextStringValueType(new NumericValueValidator(1, 10)));
|
|||
} |
|||
|
|||
protected ILocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<AbpOssManagementResource>(name); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
namespace LINGYUN.Abp.OssManagement.Features |
|||
{ |
|||
public class AbpOssManagementFeatureNames |
|||
{ |
|||
public const string GroupName = "AbpOssManagement"; |
|||
|
|||
|
|||
public class OssObject |
|||
{ |
|||
public const string Default = GroupName + ".OssObject"; |
|||
/// <summary>
|
|||
/// 下载文件功能
|
|||
/// </summary>
|
|||
public const string DownloadFile = Default + ".DownloadFile"; |
|||
/// <summary>
|
|||
/// 下载文件功能限制次数
|
|||
/// </summary>
|
|||
public const string DownloadLimit = Default + ".DownloadLimit"; |
|||
/// <summary>
|
|||
/// 下载文件功能限制次数周期
|
|||
/// </summary>
|
|||
public const string DownloadInterval = Default + ".DownloadInterval"; |
|||
/// <summary>
|
|||
/// 上传文件功能
|
|||
/// </summary>
|
|||
public const string UploadFile = Default + ".UploadFile"; |
|||
/// <summary>
|
|||
/// 上传文件功能限制次数
|
|||
/// </summary>
|
|||
public const string UploadLimit = Default + ".UploadLimit"; |
|||
/// <summary>
|
|||
/// 上传文件功能限制次数周期
|
|||
/// </summary>
|
|||
public const string UploadInterval = Default + ".UploadInterval"; |
|||
/// <summary>
|
|||
/// 最大上传文件
|
|||
/// </summary>
|
|||
public const string MaxUploadFileCount = Default + ".MaxUploadFileCount"; |
|||
} |
|||
} |
|||
} |
|||
@ -1,21 +1,21 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:30030", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"LINGYUN.Abp.LocalizationManagement.HttpApi.Host": { |
|||
"commandName": "Project", |
|||
"dotnetRunMessages": "true", |
|||
"launchBrowser": false, |
|||
"applicationUrl": "http://0.0.0.0:30030", |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:30030", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"LINGYUN.Abp.LocalizationManagement.HttpApi.Host": { |
|||
"commandName": "Project", |
|||
"dotnetRunMessages": "true", |
|||
"launchBrowser": false, |
|||
"applicationUrl": "http://0.0.0.0:30030", |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue