63 changed files with 655 additions and 469 deletions
@ -1,20 +0,0 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /><GeneratePackageOnBuild>true</GeneratePackageOnBuild> |
|||
<Version>3.0.0</Version> |
|||
<Authors>LINGYUN</Authors> |
|||
<Description>七牛云Oss对象存储Abp集成</Description> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|||
<OutputPath>D:\LocalNuget</OutputPath> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Qiniu.Shared" Version="7.2.15" /> |
|||
<PackageReference Include="Volo.Abp.BlobStoring" Version="3.0.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -1,11 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|||
{ |
|||
[DependsOn(typeof(AbpBlobStoringModule))] |
|||
public class AbpBlobStoringQiniuModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|||
{ |
|||
public class DefaultQiniuBlobNameCalculator : IQiniuBlobNameCalculator, ITransientDependency |
|||
{ |
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
|
|||
public DefaultQiniuBlobNameCalculator( |
|||
ICurrentTenant currentTenant) |
|||
{ |
|||
CurrentTenant = currentTenant; |
|||
} |
|||
|
|||
public string Calculate(BlobProviderArgs args) |
|||
{ |
|||
return CurrentTenant.Id == null |
|||
? $"host/{args.BlobName}" |
|||
: $"tenants/{CurrentTenant.Id.Value:D}/{args.BlobName}"; |
|||
} |
|||
} |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
using Volo.Abp.BlobStoring; |
|||
|
|||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|||
{ |
|||
public interface IQiniuBlobNameCalculator |
|||
{ |
|||
string Calculate(BlobProviderArgs args); |
|||
} |
|||
} |
|||
@ -1,25 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp.BlobStoring; |
|||
|
|||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|||
{ |
|||
public static class QiniuBlobContainerConfigurationExtensions |
|||
{ |
|||
public static QiniuBlobProviderConfiguration GetQiniuConfiguration( |
|||
this BlobContainerConfiguration containerConfiguration) |
|||
{ |
|||
return new QiniuBlobProviderConfiguration(containerConfiguration); |
|||
} |
|||
|
|||
public static BlobContainerConfiguration UseQiniu( |
|||
this BlobContainerConfiguration containerConfiguration, |
|||
Action<QiniuBlobProviderConfiguration> qiniuConfigureAction) |
|||
{ |
|||
containerConfiguration.ProviderType = typeof(QiniuBlobProvider); |
|||
|
|||
qiniuConfigureAction(new QiniuBlobProviderConfiguration(containerConfiguration)); |
|||
|
|||
return containerConfiguration; |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
using Qiniu.Util; |
|||
using System; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.DependencyInjection; |
|||
using QiniuConfig = Qiniu.Common.Config; |
|||
|
|||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|||
{ |
|||
public class QiniuBlobProvider : BlobProviderBase, ITransientDependency |
|||
{ |
|||
protected IQiniuBlobNameCalculator QiniuBlobNameCalculator { get; } |
|||
public override Task<bool> DeleteAsync(BlobProviderDeleteArgs args) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public override Task<bool> ExistsAsync(BlobProviderExistsArgs args) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public override Task<Stream> GetOrNullAsync(BlobProviderGetArgs args) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public override Task SaveAsync(BlobProviderSaveArgs args) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
private Mac GetMac(BlobProviderArgs args) |
|||
{ |
|||
var configuration = args.Configuration.GetQiniuConfiguration(); |
|||
return new Mac(configuration.AccessKey, configuration.SecretKey); |
|||
} |
|||
|
|||
private string GetAndInitBucketName(BlobProviderArgs args) |
|||
{ |
|||
var configuration = args.Configuration.GetQiniuConfiguration(); |
|||
var bucketName = configuration.BucketName.IsNullOrWhiteSpace() |
|||
? args.ContainerName |
|||
: configuration.BucketName; |
|||
QiniuConfig.AutoZone(configuration.AccessKey, bucketName, true); |
|||
return bucketName; |
|||
} |
|||
} |
|||
} |
|||
@ -1,85 +0,0 @@ |
|||
using Volo.Abp; |
|||
using Volo.Abp.BlobStoring; |
|||
|
|||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|||
{ |
|||
public class QiniuBlobProviderConfiguration |
|||
{ |
|||
/// <summary>
|
|||
/// Api授权码
|
|||
/// </remarks>
|
|||
public string AccessKey |
|||
{ |
|||
get => _containerConfiguration.GetConfiguration<string>(QiniuBlobProviderConfigurationNames.AccessKey); |
|||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.AccessKey, Check.NotNullOrWhiteSpace(value, nameof(value))); |
|||
} |
|||
/// <summary>
|
|||
/// Api密钥
|
|||
/// </summary>
|
|||
public string SecretKey |
|||
{ |
|||
get => _containerConfiguration.GetConfiguration<string>(QiniuBlobProviderConfigurationNames.SecretKey); |
|||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.SecretKey, Check.NotNullOrWhiteSpace(value, nameof(value))); |
|||
} |
|||
/// <summary>
|
|||
/// 默认的Bucket名称
|
|||
/// </summary>
|
|||
public string BucketName |
|||
{ |
|||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.BucketName, ""); |
|||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.BucketName, value ?? ""); |
|||
} |
|||
/// <summary>
|
|||
/// 默认自动删除该文件天数
|
|||
/// 默认 0,不删除
|
|||
/// </summary>
|
|||
public int DeleteAfterDays |
|||
{ |
|||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.DeleteAfterDays, 0); |
|||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.DeleteAfterDays, value); |
|||
} |
|||
/// <summary>
|
|||
/// 上传成功后,七牛云向业务服务器发送 POST 请求的 URL。
|
|||
/// 必须是公网上可以正常进行 POST 请求并能响应 HTTP/1.1 200 OK 的有效 URL
|
|||
/// </summary>
|
|||
public string UploadCallbackUrl |
|||
{ |
|||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.UploadCallbackUrl, ""); |
|||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.UploadCallbackUrl, value ?? ""); |
|||
} |
|||
/// <summary>
|
|||
/// 上传成功后,七牛云向业务服务器发送回调通知时的 Host 值。
|
|||
/// 与 callbackUrl 配合使用,仅当设置了 callbackUrl 时才有效。
|
|||
/// </summary>
|
|||
public string UploadCallbackHost |
|||
{ |
|||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.UploadCallbackHost, ""); |
|||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.UploadCallbackHost, value ?? ""); |
|||
} |
|||
/// <summary>
|
|||
/// 上传成功后,七牛云向业务服务器发送回调通知 callbackBody 的 Content-Type。
|
|||
/// 默认为 application/x-www-form-urlencoded,也可设置为 application/json。
|
|||
/// </summary>
|
|||
public string UploadCallbackBodyType |
|||
{ |
|||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.UploadCallbackBodyType, ""); |
|||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.UploadCallbackBodyType, value ?? ""); |
|||
} |
|||
/// <summary>
|
|||
/// 上传成功后,自定义七牛云最终返回給上传端(在指定 returnUrl 时是携带在跳转路径参数中)的数据。
|
|||
/// 支持魔法变量和自定义变量。returnBody 要求是合法的 JSON 文本。
|
|||
/// 例如 {"key": $(key), "hash": $(etag), "w": $(imageInfo.width), "h": $(imageInfo.height)}。
|
|||
/// </summary>
|
|||
public string UploadCallbackBody |
|||
{ |
|||
get => _containerConfiguration.GetConfigurationOrDefault(QiniuBlobProviderConfigurationNames.UploadCallbackBody, ""); |
|||
set => _containerConfiguration.SetConfiguration(QiniuBlobProviderConfigurationNames.UploadCallbackBody, value ?? ""); |
|||
} |
|||
private readonly BlobContainerConfiguration _containerConfiguration; |
|||
|
|||
public QiniuBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) |
|||
{ |
|||
_containerConfiguration = containerConfiguration; |
|||
} |
|||
} |
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
namespace LINGYUN.Abp.BlobStoring.Qiniu |
|||
{ |
|||
public static class QiniuBlobProviderConfigurationNames |
|||
{ |
|||
/// <summary>
|
|||
/// Api授权码
|
|||
/// </summary>
|
|||
public const string AccessKey = "Qiniu:OSS:AccessKey"; |
|||
/// <summary>
|
|||
/// Api密钥
|
|||
/// </summary>
|
|||
public const string SecretKey = "Qiniu:OSS:SecretKey"; |
|||
/// <summary>
|
|||
/// 默认的Bucket名称
|
|||
/// </summary>
|
|||
public const string BucketName = "Qiniu:OSS:BucketName"; |
|||
/// <summary>
|
|||
/// 默认自动删除该文件天数
|
|||
/// 默认 0,不删除
|
|||
/// </summary>
|
|||
public const string DeleteAfterDays = "Qiniu:OSS:DeleteAfterDays"; |
|||
/// <summary>
|
|||
/// 上传成功后,七牛云向业务服务器发送 POST 请求的 URL。
|
|||
/// 必须是公网上可以正常进行 POST 请求并能响应 HTTP/1.1 200 OK 的有效 URL
|
|||
/// </summary>
|
|||
public const string UploadCallbackUrl = "Qiniu:OSS:UploadCallbackUrl"; |
|||
/// <summary>
|
|||
/// 上传成功后,七牛云向业务服务器发送回调通知时的 Host 值。
|
|||
/// 与 callbackUrl 配合使用,仅当设置了 callbackUrl 时才有效。
|
|||
/// </summary>
|
|||
public const string UploadCallbackHost = "Qiniu:OSS:UploadCallbackHost"; |
|||
/// <summary>
|
|||
/// 上传成功后,七牛云向业务服务器发送回调通知 callbackBody 的 Content-Type。
|
|||
/// 默认为 application/x-www-form-urlencoded,也可设置为 application/json。
|
|||
/// </summary>
|
|||
public const string UploadCallbackBodyType = "Qiniu:OSS:UploadCallbackBodyType"; |
|||
/// <summary>
|
|||
/// 上传成功后,自定义七牛云最终返回給上传端(在指定 returnUrl 时是携带在跳转路径参数中)的数据。
|
|||
/// 支持魔法变量和自定义变量。returnBody 要求是合法的 JSON 文本。
|
|||
/// 例如 {"key": $(key), "hash": $(etag), "w": $(imageInfo.width), "h": $(imageInfo.height)}。
|
|||
/// </summary>
|
|||
public const string UploadCallbackBody = "Qiniu:OSS:UploadCallbackBody"; |
|||
} |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> |
|||
<Version>3.0.0</Version> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|||
<OutputPath>D:\LocalNuget</OutputPath> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Identity.Domain" Version="3.0.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -1,77 +0,0 @@ |
|||
using Microsoft.AspNetCore.Identity; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Identity.Settings; |
|||
using Volo.Abp.Options; |
|||
using Volo.Abp.Settings; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace LINGYUN.Abp.Identity |
|||
{ |
|||
public class AbpIdentityOverrideOptionsFactory : AbpOptionsFactory<IdentityOptions> |
|||
{ |
|||
protected ISettingStore SettingStore { get; } |
|||
public AbpIdentityOverrideOptionsFactory( |
|||
ISettingStore settingStore, |
|||
IEnumerable<IConfigureOptions<IdentityOptions>> setups, |
|||
IEnumerable<IPostConfigureOptions<IdentityOptions>> postConfigures) |
|||
: base(setups, postConfigures) |
|||
{ |
|||
SettingStore = settingStore; |
|||
} |
|||
|
|||
public override IdentityOptions Create(string name) |
|||
{ |
|||
var options = base.Create(name); |
|||
|
|||
// 重写为只获取公共配置
|
|||
OverrideOptions(options); |
|||
|
|||
return options; |
|||
} |
|||
|
|||
protected virtual void OverrideOptions(IdentityOptions options) |
|||
{ |
|||
AsyncHelper.RunSync(() => OverrideOptionsAsync(options)); |
|||
} |
|||
|
|||
protected virtual async Task OverrideOptionsAsync(IdentityOptions options) |
|||
{ |
|||
options.Password.RequiredLength = await GetOrDefaultAsync(IdentitySettingNames.Password.RequiredLength, options.Password.RequiredLength); |
|||
options.Password.RequiredUniqueChars = await GetOrDefaultAsync(IdentitySettingNames.Password.RequiredUniqueChars, options.Password.RequiredUniqueChars); |
|||
options.Password.RequireNonAlphanumeric = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireNonAlphanumeric, options.Password.RequireNonAlphanumeric); |
|||
options.Password.RequireLowercase = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireLowercase, options.Password.RequireLowercase); |
|||
options.Password.RequireUppercase = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireUppercase, options.Password.RequireUppercase); |
|||
options.Password.RequireDigit = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireDigit, options.Password.RequireDigit); |
|||
|
|||
options.Lockout.AllowedForNewUsers = await GetOrDefaultAsync(IdentitySettingNames.Lockout.AllowedForNewUsers, options.Lockout.AllowedForNewUsers); |
|||
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(await GetOrDefaultAsync(IdentitySettingNames.Lockout.LockoutDuration, options.Lockout.DefaultLockoutTimeSpan.TotalSeconds.To<int>())); |
|||
options.Lockout.MaxFailedAccessAttempts = await GetOrDefaultAsync(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, options.Lockout.MaxFailedAccessAttempts); |
|||
|
|||
options.SignIn.RequireConfirmedEmail = await GetOrDefaultAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail, options.SignIn.RequireConfirmedEmail); |
|||
options.SignIn.RequireConfirmedPhoneNumber = await GetOrDefaultAsync(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, options.SignIn.RequireConfirmedPhoneNumber); |
|||
} |
|||
|
|||
protected virtual async Task<T> GetOrDefaultAsync<T>(string name, T defaultValue = default(T)) where T : struct |
|||
{ |
|||
var setting = await SettingStore.GetOrNullAsync(name, GlobalSettingValueProvider.ProviderName, null); |
|||
if (setting.IsNullOrWhiteSpace()) |
|||
{ |
|||
return defaultValue; |
|||
} |
|||
return setting.To<T>(); |
|||
} |
|||
|
|||
protected virtual async Task<string> GetOrDefaultAsync(string name, string defaultValue = "") |
|||
{ |
|||
var setting = await SettingStore.GetOrNullAsync(name, GlobalSettingValueProvider.ProviderName, null); |
|||
if (setting.IsNullOrWhiteSpace()) |
|||
{ |
|||
return defaultValue; |
|||
} |
|||
return setting; |
|||
} |
|||
} |
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
using Microsoft.AspNetCore.Identity; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Identity |
|||
{ |
|||
/// <summary>
|
|||
/// 重写IdentityOptions,主要替换配置工厂组件,不再从SettingProvider获取IdentityOptions配置
|
|||
/// 在跨服务器时,从SettingProvider获取配置,用户需等待很长的时间,严重影响体验
|
|||
/// 如果是本地服务器,可以忽略这些性能影响,不需要引用此模块
|
|||
/// </summary>
|
|||
[DependsOn(typeof(AbpIdentityDomainModule))] |
|||
public class AbpIdentityOverrideOptionsModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
// TODO:配置文件指定IdentityOptions,避免从数据库读取的超长时间等待
|
|||
// 问题点:https://github.com/abpframework/abp/blob/dev/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsFactory.cs
|
|||
// 有11个同步等待任务去获取身份认证配置,如果缓存不存在,会执行11条数据库指令
|
|||
// 运行过程中严重影响体验
|
|||
context.Services.Replace(ServiceDescriptor.Transient<IOptionsFactory<IdentityOptions>, AbpIdentityOverrideOptionsFactory>()); |
|||
context.Services.Replace(ServiceDescriptor.Transient<IOptions<IdentityOptions>, OptionsManager<IdentityOptions>>()); |
|||
|
|||
var configuration = context.Services.GetConfiguration(); |
|||
Configure<IdentityOptions>(configuration.GetSection("Identity")); |
|||
Configure<IdentityOptions>(options => |
|||
{ |
|||
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(configuration.GetSection("Identity:Lockout:LockoutDuration").Get<int>()); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using LINGYUN.Platform.Localization; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Platform |
|||
{ |
|||
[DependsOn(typeof(AppPlatformDomainSharedModule))] |
|||
public class AppPlatformApplicationContractModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AppPlatformApplicationContractModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Get<PlatformResource>() |
|||
.AddVirtualJson("/LINGYUN/Platform/Localization/ApplicationContracts"); |
|||
}); |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"Permission:Platform": "Platform service", |
|||
"Permission:AppVersion": "Version management", |
|||
"Permission:FileSystem": "File system", |
|||
"Permission:FileManager": "File management", |
|||
"Permission:CreateVersion": "Create version", |
|||
"Permission:DeleteVersion": "Delete version", |
|||
"Permission:CreateFolder": "Create directory", |
|||
"Permission:DeleteFolder": "Delete directory", |
|||
"Permission:RenameFolder": "Directory rename", |
|||
"Permission:MoveFolder": "Change directory", |
|||
"Permission:CopyFolder": "Copy directory", |
|||
"Permission:AppendFile": "Add files", |
|||
"Permission:UpdateFile": "Change file", |
|||
"Permission:DeleteFile": "Delete file", |
|||
"Permission:CopyFile": "Copy file", |
|||
"Permission:MoveFile": "Move file", |
|||
"Permission:DownloadFile": "Download file" |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
"Permission:Platform": "平台服务", |
|||
"Permission:AppVersion": "版本管理", |
|||
"Permission:FileSystem": "文件系统", |
|||
"Permission:FileManager": "文件管理", |
|||
"Permission:CreateVersion": "创建版本", |
|||
"Permission:DeleteVersion": "删除版本", |
|||
"Permission:CreateFolder": "创建目录", |
|||
"Permission:DeleteFolder": "删除目录", |
|||
"Permission:RenameFolder": "目录改名", |
|||
"Permission:MoveFolder": "变更目录", |
|||
"Permission:CopyFolder": "复制目录", |
|||
"Permission:AppendFile": "添加文件", |
|||
"Permission:UpdateFile": "变更文件", |
|||
"Permission:DeleteFile": "删除文件", |
|||
"Permission:CopyFile": "复制文件", |
|||
"Permission:MoveFile": "移动文件", |
|||
"Permission:DownloadFile": "下载文件" |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using LINGYUN.Platform.Localization; |
|||
using Volo.Abp.Authorization.Permissions; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Platform.Permissions |
|||
{ |
|||
public class PlatformPermissionDefinitionProvider : PermissionDefinitionProvider |
|||
{ |
|||
public override void Define(IPermissionDefinitionContext context) |
|||
{ |
|||
var platform = context.AddGroup(PlatformPermissions.GroupName, L("Permission:Platform")); |
|||
|
|||
var appVersion = platform.AddPermission(PlatformPermissions.AppVersion.Default, L("Permission:AppVersion")); |
|||
appVersion.AddChild(PlatformPermissions.AppVersion.Create, L("Permission:CreateVersion")); |
|||
appVersion.AddChild(PlatformPermissions.AppVersion.Delete, L("Permission:DeleteVersion")); |
|||
|
|||
var versionFile = appVersion.AddChild(PlatformPermissions.AppVersion.FileManager.Default, L("Permission:FileManager")); |
|||
versionFile.AddChild(PlatformPermissions.AppVersion.FileManager.Create, L("Permission:AppendFile")); |
|||
versionFile.AddChild(PlatformPermissions.AppVersion.FileManager.Delete, L("Permission:DeleteFile")); |
|||
versionFile.AddChild(PlatformPermissions.AppVersion.FileManager.Download, L("Permission:DownloadFile")); |
|||
|
|||
// TODO: 2020-07-27 目前abp不支持对象存储管理(或者属于企业版?)需要创建一个 LINGYUN.Abp.BlobStoring 项目自行实现
|
|||
|
|||
var fileSystem = platform.AddPermission(PlatformPermissions.FileSystem.Default, L("Permission:FileSystem")); |
|||
fileSystem.AddChild(PlatformPermissions.FileSystem.Create, L("Permission:CreateFolder")); |
|||
fileSystem.AddChild(PlatformPermissions.FileSystem.Delete, L("Permission:DeleteFolder")); |
|||
fileSystem.AddChild(PlatformPermissions.FileSystem.Rename, L("Permission:RenameFolder")); |
|||
fileSystem.AddChild(PlatformPermissions.FileSystem.Copy, L("Permission:CopyFolder")); |
|||
fileSystem.AddChild(PlatformPermissions.FileSystem.Move, L("Permission:MoveFolder")); |
|||
|
|||
var fileManager = fileSystem.AddChild(PlatformPermissions.FileSystem.FileManager.Default, L("Permission:FileManager")); |
|||
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Create, L("Permission:AppendFile")); |
|||
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Update, L("Permission:UpdateFile")); |
|||
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Delete, L("Permission:DeleteFile")); |
|||
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Copy, L("Permission:CopyFile")); |
|||
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Move, L("Permission:MoveFile")); |
|||
fileManager.AddChild(PlatformPermissions.FileSystem.FileManager.Download, L("Permission:DownloadFile")); |
|||
} |
|||
|
|||
private static LocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<PlatformResource>(name); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
using Volo.Abp.Reflection; |
|||
|
|||
namespace LINGYUN.Platform.Permissions |
|||
{ |
|||
public class PlatformPermissions |
|||
{ |
|||
public const string GroupName = "Platform"; |
|||
|
|||
// 如果abp后期提供对象存储的目录管理接口,则启用此权限
|
|||
/// <summary>
|
|||
/// 文件系统
|
|||
/// </summary>
|
|||
public class FileSystem |
|||
{ |
|||
public const string Default = GroupName + ".FileSystem"; |
|||
|
|||
public const string Create = Default + ".Create"; |
|||
|
|||
public const string Delete = Default + ".Delete"; |
|||
|
|||
public const string Rename = Default + ".Rename"; |
|||
|
|||
public const string Copy = Default + ".Copy"; |
|||
|
|||
public const string Move = Default + ".Move"; |
|||
|
|||
public class FileManager |
|||
{ |
|||
public const string Default = FileSystem.Default + ".FileManager"; |
|||
|
|||
public const string Create = Default + ".Create"; |
|||
|
|||
public const string Copy = Default + ".Copy"; |
|||
|
|||
public const string Delete = Default + ".Delete"; |
|||
|
|||
public const string Update = Default + ".Update"; |
|||
|
|||
public const string Move = Default + ".Move"; |
|||
|
|||
public const string Download = Default + ".Download"; |
|||
} |
|||
} |
|||
|
|||
public class AppVersion |
|||
{ |
|||
public const string Default = GroupName + ".AppVersion"; |
|||
|
|||
public const string Create = Default + ".Create"; |
|||
|
|||
public const string Delete = Default + ".Delete"; |
|||
|
|||
public class FileManager |
|||
{ |
|||
public const string Default = AppVersion.Default + ".FileManager"; |
|||
|
|||
public const string Create = Default + ".Create"; |
|||
|
|||
public const string Delete = Default + ".Delete"; |
|||
|
|||
public const string Download = Default + ".Download"; |
|||
} |
|||
} |
|||
|
|||
public static string[] GetAll() |
|||
{ |
|||
return ReflectionHelper.GetPublicConstantsRecursively(typeof(PlatformPermissions)); |
|||
} |
|||
} |
|||
} |
|||
@ -1,10 +0,0 @@ |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Platform |
|||
{ |
|||
[DependsOn(typeof(PlatformDomainSharedModule))] |
|||
public class PlatformApplicationContractModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
namespace LINGYUN.Platform.BlobStoring |
|||
{ |
|||
public static class BlobConsts |
|||
{ |
|||
public static int MaxNameLength |
|||
{ |
|||
get; |
|||
set; |
|||
} = 255; |
|||
public static int MaxSha256Length |
|||
{ |
|||
get; |
|||
set; |
|||
} = 65; |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
namespace LINGYUN.Platform.BlobStoring |
|||
{ |
|||
public static class BlobContainerConsts |
|||
{ |
|||
public static int MaxNameLength |
|||
{ |
|||
get; |
|||
set; |
|||
} = 255; |
|||
|
|||
public static int MaxPathLength |
|||
{ |
|||
get; |
|||
set; |
|||
} = 255; |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace LINGYUN.Platform |
|||
{ |
|||
public static class PlatformErrorCodes |
|||
{ |
|||
public const string VersionFileNotFound = "Platform.VersionFile:404"; |
|||
} |
|||
} |
|||
@ -1,6 +1,6 @@ |
|||
namespace LINGYUN.Platform |
|||
{ |
|||
public static class PlatformDbProperties |
|||
public static class AppPlatformDbProperties |
|||
{ |
|||
public static string DbTablePrefix { get; set; } = "AppPlatform"; |
|||
|
|||
@ -0,0 +1,35 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Domain.Entities.Auditing; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Platform.BlobStoring |
|||
{ |
|||
public class Blob : AuditedAggregateRoot<Guid>, IMultiTenant |
|||
{ |
|||
public virtual Guid ContainerId { get; protected set; } |
|||
public virtual Guid? TenantId { get; protected set; } |
|||
public virtual string Name { get; protected set; } |
|||
public virtual string Sha256 { get; protected set; } |
|||
public virtual long Size { get; protected set; } |
|||
protected Blob() { } |
|||
public Blob(Guid id, Guid containerId, [NotNull] string name, [NotNull] string sha256, long size, Guid? tenantId) |
|||
{ |
|||
Id = id; |
|||
ContainerId = containerId; |
|||
ChangeFile(name, sha256, size); |
|||
TenantId = tenantId; |
|||
} |
|||
|
|||
public void ChangeFile(string name, string sha256, long size) |
|||
{ |
|||
Name = Check.NotNullOrWhiteSpace(name, nameof(name), BlobConsts.MaxNameLength); |
|||
Sha256 = Check.NotNullOrWhiteSpace(sha256, nameof(sha256), BlobConsts.MaxSha256Length); |
|||
Size = size; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Entities.Auditing; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.Platform.BlobStoring |
|||
{ |
|||
public class BlobContainer : AuditedAggregateRoot<Guid>, IMultiTenant |
|||
{ |
|||
public virtual Guid? TenantId { get; protected set; } |
|||
public virtual string Name { get; protected set; } |
|||
public BlobContainer(Guid id, [NotNull] string name, Guid? tenantId = null) |
|||
: base(id) |
|||
{ |
|||
Name = Check.NotNullOrWhiteSpace(name, nameof(name), BlobContainerConsts.MaxNameLength); |
|||
TenantId = tenantId; |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,71 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.BlobStoring; |
|||
using Volo.Abp.Domain.Services; |
|||
|
|||
namespace LINGYUN.Platform.BlobStoring |
|||
{ |
|||
public class BlobStoringManager : DomainService |
|||
{ |
|||
private IBlobRepository _blobRepository; |
|||
protected IBlobRepository BlobRepository => LazyGetRequiredService(ref _blobRepository); |
|||
|
|||
private IBlobContainerRepository _containerRepository; |
|||
protected IBlobContainerRepository ContainerRepository => LazyGetRequiredService(ref _containerRepository); |
|||
|
|||
protected IBlobContainerFactory BlobContainerFactory { get; } |
|||
protected IBlobContainerConfigurationProvider BlobContainerConfigurationProvider { get; } |
|||
|
|||
public virtual async Task CreateContainerAsync(string name) |
|||
{ |
|||
var containerConfiguration = BlobContainerConfigurationProvider.Get<OSSContainer>(); |
|||
var containerName = NormalizeContainerName(containerConfiguration, name); |
|||
if (await ContainerRepository.ContainerExistsAsync(name)) |
|||
{ |
|||
|
|||
} |
|||
// 框架暂时未实现创建Container ,这里采用保存一个空文件,然后删除此文件的方法来创建Container
|
|||
var blobContainer = BlobContainerFactory.Create(containerName); |
|||
try |
|||
{ |
|||
var emptyBlobData = System.Text.Encoding.UTF8.GetBytes(""); |
|||
await blobContainer.SaveAsync("empty.txt", emptyBlobData, true); |
|||
var container = new BlobContainer(GuidGenerator.Create(), containerName, CurrentTenant.Id) |
|||
{ |
|||
CreationTime = Clock.Now |
|||
}; |
|||
await ContainerRepository.InsertAsync(container); |
|||
} |
|||
finally |
|||
{ |
|||
await blobContainer.DeleteAsync("empty.txt"); |
|||
} |
|||
} |
|||
|
|||
protected virtual string NormalizeContainerName(BlobContainerConfiguration configuration, string containerName) |
|||
{ |
|||
if (!configuration.NamingNormalizers.Any()) |
|||
{ |
|||
return containerName; |
|||
} |
|||
|
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
foreach (var normalizerType in configuration.NamingNormalizers) |
|||
{ |
|||
var normalizer = scope.ServiceProvider |
|||
.GetRequiredService(normalizerType) |
|||
.As<IBlobNamingNormalizer>(); |
|||
|
|||
containerName = normalizer.NormalizeContainerName(containerName); |
|||
} |
|||
|
|||
return containerName; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace LINGYUN.Platform.BlobStoring |
|||
{ |
|||
public interface IBlobContainerRepository : IBasicRepository<BlobContainer, Guid> |
|||
{ |
|||
Task<bool> ContainerExistsAsync(string name, CancellationToken cancellationToken = default); |
|||
|
|||
Task<BlobContainer> GetByNameAsync(string name, CancellationToken cancellationToken = default); |
|||
|
|||
Task<long> GetCountAsync(string filter = "", CancellationToken cancellationToken = default); |
|||
|
|||
Task<List<BlobContainer>> GetPagedListAsync(string filter = "", string sorting = nameof(BlobContainer.Name), |
|||
int skipCount = 1, int maxResultCount = 10, CancellationToken cancellationToken = default); |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace LINGYUN.Platform.BlobStoring |
|||
{ |
|||
public interface IBlobRepository : IBasicRepository<Blob, Guid> |
|||
{ |
|||
Task<bool> BlobExistsAsync(string sha256, CancellationToken cancellationToken = default); |
|||
|
|||
Task<Blob> GetBySha256Async(string sha256, CancellationToken cancellationToken = default); |
|||
|
|||
Task CopyToAsync(Blob blob, Guid copyToContainerId, CancellationToken cancellationToken = default); |
|||
|
|||
Task MoveToAsync(Blob blob, Guid moveToContainerId, CancellationToken cancellationToken = default); |
|||
|
|||
Task<long> GetCountAsync(Guid containerId, string filter = "", CancellationToken cancellationToken = default); |
|||
|
|||
Task<List<Blob>> GetPagedListAsync(Guid containerId, string filter = "", string sorting = nameof(Blob.Name), |
|||
int skipCount = 1, int maxResultCount = 10, CancellationToken cancellationToken = default); |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.BlobStoring; |
|||
|
|||
namespace LINGYUN.Platform.BlobStoring |
|||
{ |
|||
[BlobContainerName("abp-application-oss")] |
|||
public class OSSContainer |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
using System.Security.Cryptography; |
|||
|
|||
namespace System |
|||
{ |
|||
public static class BytesExtensions |
|||
{ |
|||
public static string Md5(this byte[] data, bool lowercase = false) |
|||
{ |
|||
using (var md5 = MD5.Create()) |
|||
{ |
|||
var hashBytes = md5.ComputeHash(data); |
|||
var md5Str = BitConverter.ToString(hashBytes).Replace("-", string.Empty); |
|||
return lowercase ? md5Str.ToLower() : md5Str; |
|||
} |
|||
} |
|||
|
|||
public static string Sha1(this byte[] data, bool lowercase = false) |
|||
{ |
|||
using (var sha = SHA1.Create()) |
|||
{ |
|||
var hashBytes = sha.ComputeHash(data); |
|||
var sha1 = BitConverter.ToString(hashBytes).Replace("-", string.Empty); |
|||
return lowercase ? sha1.ToLower() : sha1; |
|||
} |
|||
} |
|||
|
|||
public static string Sha256(this byte[] data, bool lowercase = false) |
|||
{ |
|||
using (var sha = SHA256.Create()) |
|||
{ |
|||
var hashBytes = sha.ComputeHash(data); |
|||
var sha256 = BitConverter.ToString(hashBytes).Replace("-", string.Empty); |
|||
return lowercase ? sha256.ToLower() : sha256; |
|||
} |
|||
} |
|||
|
|||
public static string Sha512(this byte[] data, bool lowercase = false) |
|||
{ |
|||
using (var sha = SHA512.Create()) |
|||
{ |
|||
var hashBytes = sha.ComputeHash(data); |
|||
var sha512 = BitConverter.ToString(hashBytes).Replace("-", string.Empty); |
|||
return lowercase ? sha512.ToLower() : sha512; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
4
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformModelBuilderConfigurationOptions.cs → aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/AppPlatformModelBuilderConfigurationOptions.cs
4
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformModelBuilderConfigurationOptions.cs → aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/AppPlatformModelBuilderConfigurationOptions.cs
@ -0,0 +1,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp3.1</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.EntityFrameworkCore" Version="3.0.0" /> |
|||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.5" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,36 @@ |
|||
using LINGYUN.Abp.Tests; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Uow; |
|||
|
|||
namespace LINGYUN.Abp.EntityFrameworkCore.Tests |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpTestsBaseModule) |
|||
)] |
|||
public class AbpEntityFrameworkCoreTestModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddEntityFrameworkInMemoryDatabase(); |
|||
|
|||
var databaseName = Guid.NewGuid().ToString(); |
|||
|
|||
Configure<AbpDbContextOptions>(options => |
|||
{ |
|||
options.Configure(abpDbContextConfigurationContext => |
|||
{ |
|||
abpDbContextConfigurationContext.DbContextOptions.UseInMemoryDatabase(databaseName); |
|||
}); |
|||
}); |
|||
|
|||
Configure<AbpUnitOfWorkDefaultOptions>(options => |
|||
{ |
|||
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; //EF in-memory database does not support transactions
|
|||
}); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue