28 changed files with 864 additions and 94 deletions
@ -0,0 +1,41 @@ |
|||||
|
using System.Text.Json; |
||||
|
|
||||
|
namespace Lion.AbpPro.Cli.Auth; |
||||
|
|
||||
|
public class ConfigService : IConfigService, ITransientDependency |
||||
|
{ |
||||
|
private readonly IJsonSerializer _jsonSerializer; |
||||
|
|
||||
|
public ConfigService(IJsonSerializer jsonSerializer) |
||||
|
{ |
||||
|
_jsonSerializer = jsonSerializer; |
||||
|
} |
||||
|
|
||||
|
public async Task SetAsync(string config) |
||||
|
{ |
||||
|
if (!Directory.Exists(CliPaths.Root)) |
||||
|
{ |
||||
|
Directory.CreateDirectory(CliPaths.Root); |
||||
|
} |
||||
|
|
||||
|
await File.WriteAllTextAsync(CliPaths.Config, config, Encoding.UTF8); |
||||
|
} |
||||
|
|
||||
|
public async Task<ConfigOptions> GetAsync() |
||||
|
{ |
||||
|
if (!File.Exists(CliPaths.Config)) |
||||
|
{ |
||||
|
return new ConfigOptions() |
||||
|
{ |
||||
|
CodeServiceUrl = "http://182.43.18.151:44317", |
||||
|
UserName = "admin", |
||||
|
Password = "1q2w3E*", |
||||
|
TenantName = string.Empty, |
||||
|
TenantId = string.Empty |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
var content = await File.ReadAllTextAsync(CliPaths.Config); |
||||
|
return _jsonSerializer.Deserialize<ConfigOptions>(content); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
namespace Lion.AbpPro.Cli.Auth; |
||||
|
|
||||
|
public interface IConfigService |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 设置token
|
||||
|
/// </summary>
|
||||
|
Task SetAsync(string config); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取token
|
||||
|
/// </summary>
|
||||
|
Task<ConfigOptions> GetAsync(); |
||||
|
} |
||||
@ -0,0 +1,73 @@ |
|||||
|
using Lion.AbpPro.Cli.Auth; |
||||
|
|
||||
|
namespace Lion.AbpPro.Cli.Commands; |
||||
|
|
||||
|
public class ConfigCommand : IConsoleCommand, ITransientDependency |
||||
|
{ |
||||
|
public const string Name = "config"; |
||||
|
private readonly ILogger<ConfigCommand> _logger; |
||||
|
private readonly IConfigService _configService; |
||||
|
private readonly IJsonSerializer _jsonSerializer; |
||||
|
private readonly ICodeService _codeService; |
||||
|
|
||||
|
public ConfigCommand(ILogger<ConfigCommand> logger, IConfigService configService, IJsonSerializer jsonSerializer, ICodeService codeService) |
||||
|
{ |
||||
|
_logger = logger; |
||||
|
_configService = configService; |
||||
|
_jsonSerializer = jsonSerializer; |
||||
|
_codeService = codeService; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// config -c http://182.43.18.151:44317 -u admin -p 1q2w3E* -t ss
|
||||
|
/// </summary>
|
||||
|
public async Task ExecuteAsync(CommandLineArgs commandLineArgs) |
||||
|
{ |
||||
|
// 获取参数
|
||||
|
var url = commandLineArgs.Options.GetOrNull(CommandOptions.CodeServiceUrl.Short, CommandOptions.CodeServiceUrl.Long); |
||||
|
var userName = commandLineArgs.Options.GetOrNull(CommandOptions.UserName.Short, CommandOptions.UserName.Long); |
||||
|
var password = commandLineArgs.Options.GetOrNull(CommandOptions.Password.Short, CommandOptions.Password.Long); |
||||
|
var tenantName = commandLineArgs.Options.GetOrNull(CommandOptions.TenantName.Short, CommandOptions.TenantName.Long); |
||||
|
|
||||
|
//1 判断url是否有效
|
||||
|
await _codeService.CheckHealthAsync(url); |
||||
|
|
||||
|
var tenantId = string.Empty; |
||||
|
//2 判断租户是否存在
|
||||
|
if (!tenantName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
var tenant = await _codeService.FindTenantAsync(url, tenantName); |
||||
|
tenantId = tenant.TenantId.ToString(); |
||||
|
} |
||||
|
|
||||
|
//3. 判断用户是否存在
|
||||
|
await _codeService.LoginAsync(url, userName, password); |
||||
|
|
||||
|
var content = new ConfigOptions() |
||||
|
{ |
||||
|
CodeServiceUrl = url, |
||||
|
UserName = userName, |
||||
|
Password = password, |
||||
|
TenantName = tenantName, |
||||
|
TenantId = tenantId |
||||
|
}; |
||||
|
await _configService.SetAsync(_jsonSerializer.Serialize(content)); |
||||
|
AnsiConsole.MarkupLine("[green]恭喜你,恭喜你设置config成功![/]"); |
||||
|
} |
||||
|
|
||||
|
public void GetUsageInfo() |
||||
|
{ |
||||
|
var sb = new StringBuilder(); |
||||
|
sb.AppendLine(""); |
||||
|
sb.AppendLine("Usage:"); |
||||
|
sb.AppendLine(" lion.abp config"); |
||||
|
sb.AppendLine(""); |
||||
|
sb.AppendLine("配置: lion.abp config"); |
||||
|
_logger.LogInformation(sb.ToString()); |
||||
|
} |
||||
|
|
||||
|
public string GetShortDescription() |
||||
|
{ |
||||
|
return "配置: lion.abp config -c http://182.43.18.151:44317 -u admin -p 1q2w3E* -t test"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
namespace Lion.AbpPro.Cli.Dto; |
||||
|
|
||||
|
public class ErrorResponse |
||||
|
{ |
||||
|
public Error error { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class Error |
||||
|
{ |
||||
|
public object code { get; set; } |
||||
|
public string message { get; set; } |
||||
|
public object details { get; set; } |
||||
|
public object data { get; set; } |
||||
|
public object validationErrors { get; set; } |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace Lion.AbpPro.Cli.Dto; |
||||
|
|
||||
|
public class FindTenantResponse |
||||
|
{ |
||||
|
public Guid? TenantId { get; set; } |
||||
|
|
||||
|
public bool Success { get; set; } |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
namespace Lion.AbpPro.Cli.Dto; |
||||
|
|
||||
|
public class GetProjectAndEntityResponse |
||||
|
{ |
||||
|
public GetProjectAndEntityResponse() |
||||
|
{ |
||||
|
Entities = new List<EntityOutput>(); |
||||
|
} |
||||
|
|
||||
|
public ProjectOutput Project { get; set; } |
||||
|
|
||||
|
public List<EntityOutput> Entities { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class ProjectOutput |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 公司名称
|
||||
|
/// </summary>
|
||||
|
public string CompanyName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 项目名称
|
||||
|
/// </summary>
|
||||
|
public string ProjectName { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class EntityOutput |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 编码
|
||||
|
/// </summary>
|
||||
|
public string Code { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 描述
|
||||
|
/// </summary>
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 首字母小写
|
||||
|
/// </summary>
|
||||
|
public string CodeCamelCase { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 复数形式
|
||||
|
/// </summary>
|
||||
|
public string CodePluralized { get; set; } |
||||
|
} |
||||
@ -1,8 +1,19 @@ |
|||||
|
using Lion.AbpPro.Cli.Dto; |
||||
|
|
||||
namespace Lion.AbpPro.Cli; |
namespace Lion.AbpPro.Cli; |
||||
|
|
||||
public interface ICodeService |
public interface ICodeService |
||||
{ |
{ |
||||
Task<string> GetAccessTokenAsync(); |
Task<string> GetAccessTokenAsync(); |
||||
|
|
||||
Task<string> DownloadAsync(string accessToken, Guid projectId, Guid templateId); |
Task<string> DownloadAsync(string accessToken, Guid projectId, Guid templateId, List<Guid> entityId); |
||||
|
|
||||
|
Task<GetProjectAndEntityResponse> GetProjectAndEntityAsync(string accessToken, Guid projectId); |
||||
|
|
||||
|
|
||||
|
Task CheckHealthAsync(string url); |
||||
|
|
||||
|
Task<FindTenantResponse> FindTenantAsync(string url, string tenantName); |
||||
|
|
||||
|
Task<string> LoginAsync(string url, string userName, string password); |
||||
} |
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
namespace Lion.AbpPro.Cli.Options; |
||||
|
|
||||
|
public class ConfigOptions |
||||
|
{ |
||||
|
public string CodeServiceUrl { get; set; } |
||||
|
|
||||
|
public string UserName { get; set; } |
||||
|
|
||||
|
public string Password { get; set; } |
||||
|
|
||||
|
public string TenantName { get; set; } |
||||
|
|
||||
|
public string TenantId { get; set; } |
||||
|
} |
||||
@ -0,0 +1,154 @@ |
|||||
|
using Microsoft.CodeAnalysis; |
||||
|
using Microsoft.CodeAnalysis.CSharp; |
||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax; |
||||
|
using Microsoft.CodeAnalysis.Text; |
||||
|
|
||||
|
namespace Lion.AbpPro.Cli.Utils; |
||||
|
|
||||
|
public static class CodeHelper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 把指定代码添加到对应方法中
|
||||
|
/// </summary>
|
||||
|
public static void AddCodeToMethod(string filePath, string methodName, string addCode) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
// 读取文件内容
|
||||
|
var code = File.ReadAllText(filePath); |
||||
|
|
||||
|
// 解析代码为语法树
|
||||
|
var tree = CSharpSyntaxTree.ParseText(code); |
||||
|
var root = tree.GetCompilationUnitRoot(); |
||||
|
|
||||
|
// 查找所有的方法声明
|
||||
|
var methodDeclarations = root.DescendantNodes().OfType<MethodDeclarationSyntax>(); |
||||
|
|
||||
|
// 筛选出名为 ConfigureOA 的方法
|
||||
|
var configureOAMethod = methodDeclarations.FirstOrDefault(m => m.Identifier.ValueText == methodName); |
||||
|
|
||||
|
if (configureOAMethod == null) return; |
||||
|
// 解析要添加的代码为语句
|
||||
|
var newStatement = CSharpSyntaxTree.ParseText(addCode).GetCompilationUnitRoot().DescendantNodes().OfType<StatementSyntax>().FirstOrDefault(); |
||||
|
|
||||
|
if (newStatement == null) return; |
||||
|
// 在方法体中添加新语句
|
||||
|
var newMethodBody = configureOAMethod?.Body?.AddStatements(newStatement); |
||||
|
var newMethod = configureOAMethod.WithBody(newMethodBody); |
||||
|
|
||||
|
// 替换原方法为新方法
|
||||
|
var newRoot = root.ReplaceNode(configureOAMethod, newMethod); |
||||
|
|
||||
|
// 获取更新后的代码文本
|
||||
|
var newCode = newRoot.GetText().ToString(); |
||||
|
// 将更新后的代码写回文件
|
||||
|
File.WriteAllText(filePath, newCode); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
throw new UserFriendlyException($"发生错误AddCodeToMethod: {ex.Message}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void AddCodeToClass(string filePath, string className, string addCode) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
// 读取文件内容
|
||||
|
var code = File.ReadAllText(filePath); |
||||
|
// 解析代码为语法树
|
||||
|
var tree = CSharpSyntaxTree.ParseText(code); |
||||
|
var root = tree.GetCompilationUnitRoot(); |
||||
|
|
||||
|
// 查找 IOADbContext 接口声明
|
||||
|
var interfaceDeclaration = root.DescendantNodes().OfType<ClassDeclarationSyntax>() |
||||
|
.FirstOrDefault(i => i.Identifier.ValueText == className); |
||||
|
|
||||
|
if (interfaceDeclaration == null) return; |
||||
|
// 解析要添加的属性代码
|
||||
|
var newProperty = CSharpSyntaxTree.ParseText(addCode).GetCompilationUnitRoot() |
||||
|
.DescendantNodes().OfType<PropertyDeclarationSyntax>().FirstOrDefault(); |
||||
|
|
||||
|
if (newProperty == null) return; |
||||
|
// 在接口成员中添加新属性
|
||||
|
var newMembers = interfaceDeclaration.Members.Add(newProperty); |
||||
|
var newInterface = interfaceDeclaration.WithMembers(newMembers); |
||||
|
|
||||
|
// 替换原接口声明为新接口声明
|
||||
|
var newRoot = root.ReplaceNode(interfaceDeclaration, newInterface); |
||||
|
|
||||
|
// 获取更新后的代码文本
|
||||
|
var newCode = newRoot.GetText().ToString(); |
||||
|
// 将更新后的代码写回文件
|
||||
|
File.WriteAllText(filePath, newCode); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
throw new UserFriendlyException($"发生错误AddCodeToClass: {ex.Message}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void AddCodeToInterface(string filePath, string interfaceName, string addCode) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
// 读取文件内容
|
||||
|
var code = File.ReadAllText(filePath); |
||||
|
|
||||
|
// 解析代码为语法树
|
||||
|
var tree = CSharpSyntaxTree.ParseText(code); |
||||
|
var root = tree.GetCompilationUnitRoot(); |
||||
|
|
||||
|
// 查找 IOADbContext 接口声明
|
||||
|
var interfaceDeclaration = root.DescendantNodes().OfType<InterfaceDeclarationSyntax>() |
||||
|
.FirstOrDefault(i => i.Identifier.ValueText == interfaceName); |
||||
|
|
||||
|
if (interfaceDeclaration == null) return; |
||||
|
// 解析要添加的属性代码
|
||||
|
var newProperty = CSharpSyntaxTree.ParseText(addCode).GetCompilationUnitRoot() |
||||
|
.DescendantNodes().OfType<PropertyDeclarationSyntax>().FirstOrDefault(); |
||||
|
|
||||
|
if (newProperty == null) return; |
||||
|
// 在接口成员中添加新属性
|
||||
|
var newMembers = interfaceDeclaration.Members.Add(newProperty); |
||||
|
var newInterface = interfaceDeclaration.WithMembers(newMembers); |
||||
|
|
||||
|
// 替换原接口声明为新接口声明
|
||||
|
var newRoot = root.ReplaceNode(interfaceDeclaration, newInterface); |
||||
|
|
||||
|
// 获取更新后的代码文本
|
||||
|
var newCode = newRoot.GetText().ToString(); |
||||
|
// 将更新后的代码写回文件
|
||||
|
File.WriteAllText(filePath, newCode); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
throw new UserFriendlyException($"发生错误AddCodeToInterface: {ex.Message}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void AddUsing(string filePath, string addCode) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
// 读取文件内容
|
||||
|
var code = File.ReadAllText(filePath); |
||||
|
|
||||
|
// 在第一行添加代码
|
||||
|
var newSourceText = SourceText.From(addCode + Environment.NewLine + code); |
||||
|
|
||||
|
// 将修改后的内容写回文件
|
||||
|
File.WriteAllText(filePath, newSourceText.ToString()); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
throw new UserFriendlyException($"发生错误AddUsing: {ex.Message}"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static bool IsExistCode(string filePath, string code) |
||||
|
{ |
||||
|
var content = File.ReadAllText(filePath).Replace(" ", ""); |
||||
|
return content.Contains(code.Replace(" ","").Replace("\r\n","")); |
||||
|
} |
||||
|
} |
||||
@ -1,6 +1,6 @@ |
|||||
namespace Lion.AbpPro |
namespace Lion.AbpPro |
||||
{ |
{ |
||||
public static class AbpProConsts |
public static class AbpProDbProperties |
||||
{ |
{ |
||||
public const string DbTablePrefix = "App"; |
public const string DbTablePrefix = "App"; |
||||
|
|
||||
@ -1,19 +1,11 @@ |
|||||
namespace Lion.AbpPro.EntityFrameworkCore |
using Volo.Abp.EntityFrameworkCore.Modeling; |
||||
{ |
|
||||
public static class AbpProDbContextModelCreatingExtensions |
|
||||
{ |
|
||||
public static void ConfigureAbpPro(this ModelBuilder builder) |
|
||||
{ |
|
||||
Check.NotNull(builder, nameof(builder)); |
|
||||
|
|
||||
/* Configure your own tables/entities inside here */ |
namespace Lion.AbpPro.EntityFrameworkCore; |
||||
|
|
||||
//builder.Entity<YourEntity>(b =>
|
public static class AbpProDbContextModelCreatingExtensions |
||||
//{
|
{ |
||||
// b.ToTable(AbpProConsts.DbTablePrefix + "YourEntities", AbpProConsts.DbSchema);
|
public static void ConfigureAbpPro(this ModelBuilder builder) |
||||
// b.ConfigureByConvention(); //auto configure for the base class props
|
{ |
||||
// //...
|
Check.NotNull(builder, nameof(builder)); |
||||
//});
|
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
@ -1,8 +1,8 @@ |
|||||
namespace MyCompanyName.MyProjectName |
namespace MyCompanyName.MyProjectName |
||||
{ |
{ |
||||
public static class MyProjectNameConsts |
public static class MyProjectNameProperties |
||||
{ |
{ |
||||
public const string DbTablePrefix = "App"; |
public const string DbTablePrefix = "Abp"; |
||||
|
|
||||
public const string DbSchema = null; |
public const string DbSchema = null; |
||||
} |
} |
||||
@ -1,19 +1,11 @@ |
|||||
namespace MyCompanyName.MyProjectName.EntityFrameworkCore |
using Volo.Abp.EntityFrameworkCore.Modeling; |
||||
{ |
|
||||
public static class MyProjectNameDbContextModelCreatingExtensions |
|
||||
{ |
|
||||
public static void ConfigureMyProjectName(this ModelBuilder builder) |
|
||||
{ |
|
||||
Check.NotNull(builder, nameof(builder)); |
|
||||
|
|
||||
/* Configure your own tables/entities inside here */ |
namespace MyCompanyName.MyProjectName.EntityFrameworkCore; |
||||
|
|
||||
//builder.Entity<YourEntity>(b =>
|
public static class MyProjectNameDbContextModelCreatingExtensions |
||||
//{
|
{ |
||||
// b.ToTable(MyProjectNameConsts.DbTablePrefix + "YourEntities", MyProjectNameConsts.DbSchema);
|
public static void ConfigureMyProjectName(this ModelBuilder builder) |
||||
// b.ConfigureByConvention(); //auto configure for the base class props
|
{ |
||||
// //...
|
Check.NotNull(builder, nameof(builder)); |
||||
//});
|
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
Loading…
Reference in new issue