Skip to content

Commit

Permalink
添加功能自动创建,更新,删除
Browse files Browse the repository at this point in the history
  • Loading branch information
lurudong committed Jun 21, 2020
1 parent 1da27d7 commit 0bf4840
Show file tree
Hide file tree
Showing 18 changed files with 489 additions and 11 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*.cs]

# Default severity for all analyzer diagnostics
dotnet_analyzer_diagnostic.severity = none
2 changes: 1 addition & 1 deletion Destiny.Core.Flow.sln
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Destiny.Core.Flow.Repositor
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Destiny.Core.Aop", "src\Destiny.Core.Aop\Destiny.Core.Aop.csproj", "{DCC8964D-54DB-4E64-ADCD-93D392477766}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Destiny.Core.Flow.FluentValidation", "src\Destiny.Core.Flow.FluentValidation\Destiny.Core.Flow.FluentValidation.csproj", "{C59766D4-9399-4048-81AD-67626B3CD87B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Destiny.Core.Flow.FluentValidation", "src\Destiny.Core.Flow.FluentValidation\Destiny.Core.Flow.FluentValidation.csproj", "{C59766D4-9399-4048-81AD-67626B3CD87B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public async Task<AjaxResult> UpdateAsync(DataDictionnaryInputDto input)
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
[Description("异步创建菜单")]
public async Task<AjaxResult> CreateAsync([FromBody]DataDictionnaryInputDto dto)
{
return (await _dataDictionnaryServices.CreateAsync(dto)).ToAjaxResult();
Expand Down
14 changes: 14 additions & 0 deletions src/Destiny.Core.Flow.API/Startups/FunctionModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Destiny.Core.Flow.AspNetCore.Api;
using Destiny.Core.Flow.Model.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Destiny.Core.Flow.API.Startups
{
public class FunctionModule: FunctionModuleBase<ApiControllerBase>
{

}
}
4 changes: 2 additions & 2 deletions src/Destiny.Core.Flow.EntityFrameworkCore/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ public int Update(TEntity entity)
/// <param name="updateExpression"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<int> UpdateBatchAsync(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TEntity>> updateExpression, CancellationToken cancellationToken = default(CancellationToken))
public virtual async Task<int> UpdateBatchAsync(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TEntity>> updateExpression, CancellationToken cancellationToken = default)
{


Expand Down Expand Up @@ -375,7 +375,7 @@ public virtual int Delete(params TEntity[] entitys)
/// </summary>
/// <param name="predicate">查询条件谓语表达式</param>
/// <returns>操作影响的行数</returns>
public virtual async Task<int> DeleteBatchAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken))
public virtual async Task<int> DeleteBatchAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
{

predicate.NotNull(nameof(predicate));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public interface IEFCoreRepository<TEntity, TPrimaryKey>
/// </summary>
/// <param name="predicate">查询条件谓语表达式</param>
/// <returns>操作影响的行数</returns>
Task<int> DeleteBatchAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken));
Task<int> DeleteBatchAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

/// <summary>
/// 删除
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
<None Remove="Te\**" />
</ItemGroup>

<ItemGroup>
<None Include="..\..\.editorconfig" Link=".editorconfig" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Destiny.Core.Flow.AspNetCore\Destiny.Core.Flow.AspNetCore.csproj" />
<ProjectReference Include="..\Destiny.Core.Flow.Dtos\Destiny.Core.Flow.Dtos.csproj" />
Expand Down
231 changes: 231 additions & 0 deletions src/Destiny.Core.Flow.Model/Security/FunctionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
using Destiny.Core.Flow.Data.Core;
using Destiny.Core.Flow.Dependency;
using Destiny.Core.Flow.Reflection;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Destiny.Core.Flow.Extensions;
using Microsoft.Extensions.Logging;
using Destiny.Core.Flow.Exceptions;
using System.Reflection;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Destiny.Core.Flow.Model.Entities.Function;
using System.Threading.Tasks;

namespace Destiny.Core.Flow.Model.Security
{
//[Dependency(ServiceLifetime.Scoped)]
public class FunctionHandler : IFunctionHandler
{

private readonly IAssemblyFinder _assemblyFinder = null;
private readonly ILogger _logger = null;

private readonly IActionDescriptorCollectionProvider _actionProvider = null;
private readonly IServiceProvider _serviceProvider = null;


public FunctionHandler(IAssemblyFinder assemblyFinder, ILoggerFactory loggerFactory, IActionDescriptorCollectionProvider actionProvider, IServiceProvider serviceProvider)
{
_assemblyFinder = assemblyFinder;
_logger = loggerFactory.CreateLogger(typeof(FunctionHandler));
_actionProvider = actionProvider;
_serviceProvider = serviceProvider;
}

/// <summary>
/// 每次查询全表比较慢。。。。。
/// </summary>
/// <typeparam name="BaseType"></typeparam>
public void Initialize<BaseType>()
{
var tyeps = _assemblyFinder.FindAll().SelectMany(o => o.GetTypes()).Where(o => o.IsController() && o.IsBaseOn<BaseType>()).ToArray();
var functionInfos = GetFunctions(tyeps);
this.SavaData(functionInfos);
}

private void SavaData(IEnumerable<FunctionInfo> functionInfos)
{
if (!functionInfos.Any())
{
return;
}
_serviceProvider.CreateScoped<IEFCoreRepository<Function, Guid>>(repository =>
{
var fcutionSelector = functionInfos.Select(o => o.Controller + o.Action);
var dbFcutions = repository.Entities.ToList();
var deleteDbFcutions = dbFcutions.Where(o => !fcutionSelector.Contains(o.Controller + o.Action)).ToArray();
var addDbActions = functionInfos.Where(db => !dbFcutions.Select(o => o.Controller + o.Action).Contains(db.Controller + db.Action)).ToArray();
repository.UnitOfWork.BeginTransaction();
if (deleteDbFcutions.Any())
{

repository.Delete(deleteDbFcutions);
_logger.LogInformation($"已删除【{deleteDbFcutions.Select(o => o.Name).ToJoin("、")}】功能,删除成功{deleteDbFcutions.Length}条");
}

if (addDbActions.Any())
{
repository.Insert(this.AddFunctions(addDbActions));
_logger.LogInformation($"添加【{addDbActions.Select(o => o.Name).ToJoin("、")}】功能,添加成功{addDbActions.Length}条");
}

var updateDbFcutions = dbFcutions.Except(deleteDbFcutions);


if (updateDbFcutions.Any())
{

this.UpdateFunctions(updateDbFcutions,functionInfos,repository);
}
repository.UnitOfWork.Commit();
});
}

private void UpdateFunctions(IEnumerable<Function> updatFunction, IEnumerable<FunctionInfo> functionInfos, IEFCoreRepository<Function, Guid> repository)
{

foreach (var function in updatFunction)
{


FunctionInfo functionInfo = functionInfos.FirstOrDefault(o =>
string.Equals(o.Controller, function.Controller, StringComparison.OrdinalIgnoreCase)
&& string.Equals(o.Action, function.Action, StringComparison.OrdinalIgnoreCase)
);
if (functionInfo == null)
{
continue;
}

bool isUpdate = false;

if (function.Controller != functionInfo.Controller)
{
isUpdate = true;
function.Controller = functionInfo.Controller;
}

if (function.Action != functionInfo.Action)
{
isUpdate = true;
function.Action = functionInfo.Action;
}

if (function.Name != functionInfo.Name)
{
isUpdate = true;
function.Name = functionInfo.Name;
}

if (isUpdate)
{
repository.Update(function);
_logger.LogInformation($"更新【{function.Name}】名字,控制器:【{function.Controller}】,方法:【{function.Action}】功能");
}

}
}

private Function[] AddFunctions(IEnumerable<FunctionInfo> functionInfos)
{
List<Function> addFunctions = new List<Function>();
foreach (var functionInfo in functionInfos)
{
addFunctions.Add(this.MapToEntity(functionInfo));
}
return addFunctions.ToArray();
}

private Function MapToEntity(FunctionInfo model)
{

return new Function
{
Name = model.Name,
Controller = model.Controller,
Action = model.Action,
Description = model.Description,
IsEnabled = true,
};
}
private FunctionInfo[] GetFunctions(Type[] types)
{
List<FunctionInfo> functions = new List<FunctionInfo>();
foreach (var type in types.OrderBy(o => o.FullName))
{
var controller = GetController(type);
if (controller is null)
{
continue;
}
if (!functions.Any(o => controller.Name.Equals(o.Name, StringComparison.OrdinalIgnoreCase) &&
controller.Controller.Equals(o.Controller, StringComparison.OrdinalIgnoreCase)))
{
functions.Add(controller);
}

var actions = this.GetControllerActions(type);

foreach (var method in actions)
{
var action = this.GetAction(controller, method);
if (action is null)
{
continue;
}
if (!functions.Any(o => action.Name.Equals(o.Name, StringComparison.OrdinalIgnoreCase) &&
action.Controller.Equals(o.Controller, StringComparison.OrdinalIgnoreCase)))
{
functions.Add(action);
}

}

}
return functions.ToArray();
}

/// <summary>
/// 得到控制下所有方法集合
/// </summary>
/// <returns></returns>
private IEnumerable<MethodInfo> GetControllerActions(Type type)
{
return type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
}

private FunctionInfo GetController(Type type)
{

if (!type.IsController())
{

throw new AppException($"此类型{type.FullName}不是控制器!");
}

var controller = type.Name.Replace("ControllerBase", string.Empty).Replace("Controller", string.Empty);
return new FunctionInfo()
{
Name = type.ToDescription(),
Controller = controller,

};
}

private FunctionInfo GetAction(FunctionInfo function, MethodInfo method)
{
return new FunctionInfo
{
Name = $"{function.Name}-{method.ToDescription()}",
Controller = function.Controller,
Action = method.Name,
};
}


}
}
32 changes: 32 additions & 0 deletions src/Destiny.Core.Flow.Model/Security/FunctionModuleBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Destiny.Core.Flow.Extensions;
using Destiny.Core.Flow.Modules;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;

namespace Destiny.Core.Flow.Model.Security
{
/// <summary>
///
/// </summary>
/// <typeparam name="BaseType"></typeparam>
public abstract class FunctionModuleBase<BaseType> : AppModuleBase
{

public override IServiceCollection ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFunctionHandler, FunctionHandler>();


return services;
}

public override void Configure(IApplicationBuilder applicationBuilder)
{
applicationBuilder.ApplicationServices.GetService<IFunctionHandler>(t => t.Initialize<BaseType>());
}
}
}
11 changes: 11 additions & 0 deletions src/Destiny.Core.Flow.Model/Security/IFunctionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Destiny.Core.Flow.Model.Security
{
public interface IFunctionHandler
{
void Initialize<BaseType>();
}
}
10 changes: 8 additions & 2 deletions src/Destiny.Core.Flow.Services/Functions/FunctionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,16 @@ public async Task<OperationResponse<FunctionOutputDto>> LoadFormFunctionAsync(Gu
return new OperationResponse<FunctionOutputDto>("加载成功", functionDto, OperationResponseType.Success);
}

public Task<OperationResponse> UpdateAsync(FunctionInputDto dto)
public async Task<OperationResponse> UpdateAsync(FunctionInputDto dto)
{
dto.NotNull(nameof(dto));
return _functionRepository.UpdateAsync(dto);
return await _functionRepository.UpdateAsync(dto,async (f,e)=> {
bool isExist = await this.Entities.Where(o =>o.Id!=f.Id&& o.Controller.ToLower() == f.Controller.ToLower() && o.Action.ToLower() == f.Action.ToLower()).AnyAsync();
if (isExist)
{
throw new AppException("此功能已存在!!!");
}
});
}
}
}
22 changes: 22 additions & 0 deletions src/Destiny.Core.Flow/Data/Core/FunctionInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Destiny.Core.Flow.Data.Core
{
public class FunctionInfo
{
public string Name { get; set; }


public string Controller { get; set; }


public string Action { get; set; }


public bool IsEnabled { get; set; }

public string Description { get; set; }
}
}
Loading

0 comments on commit 0bf4840

Please sign in to comment.