diff --git a/Apimanager_backend.sln b/Apimanager_backend.sln index 36300f7..f67a888 100644 --- a/Apimanager_backend.sln +++ b/Apimanager_backend.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.11.35312.102 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apimanager_backend", "Apimanager_backend\Apimanager_backend.csproj", "{F4FD5145-6971-4032-B2B6-D7A61AF8BB2E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Apimanager_backend", "Apimanager_backend\Apimanager_backend.csproj", "{F4FD5145-6971-4032-B2B6-D7A61AF8BB2E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Public", "Public\Public.csproj", "{3B2063E0-B7B1-4CCF-979C-0E533FE1A05E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {F4FD5145-6971-4032-B2B6-D7A61AF8BB2E}.Debug|Any CPU.Build.0 = Debug|Any CPU {F4FD5145-6971-4032-B2B6-D7A61AF8BB2E}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4FD5145-6971-4032-B2B6-D7A61AF8BB2E}.Release|Any CPU.Build.0 = Release|Any CPU + {3B2063E0-B7B1-4CCF-979C-0E533FE1A05E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B2063E0-B7B1-4CCF-979C-0E533FE1A05E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B2063E0-B7B1-4CCF-979C-0E533FE1A05E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B2063E0-B7B1-4CCF-979C-0E533FE1A05E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Apimanager_backend/ApiHandler/TestHandle.dll b/Apimanager_backend/ApiHandler/TestHandle.dll new file mode 100644 index 0000000..8f80be3 Binary files /dev/null and b/Apimanager_backend/ApiHandler/TestHandle.dll differ diff --git a/Apimanager_backend/Apimanager_backend.csproj b/Apimanager_backend/Apimanager_backend.csproj index 059696b..bf92279 100644 --- a/Apimanager_backend/Apimanager_backend.csproj +++ b/Apimanager_backend/Apimanager_backend.csproj @@ -19,8 +19,14 @@ + + + + + + diff --git a/Apimanager_backend/Config/MyAutomapper.cs b/Apimanager_backend/Config/MyAutomapper.cs index f0895eb..e032e04 100644 --- a/Apimanager_backend/Config/MyAutomapper.cs +++ b/Apimanager_backend/Config/MyAutomapper.cs @@ -15,6 +15,14 @@ namespace Apimanager_backend.Config CreateMap(); CreateMap(); CreateMap(); + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(dest => dest.Success, opt => opt.MapFrom(src => src.code == 1)) + .ForMember(dest => dest.QrCode, opt => opt.MapFrom(src => src.qrcode)) + .ForMember(dest => dest.OrderNum, opt => opt.MapFrom(src => src.trade_no)) + .ForMember(dest => dest.PayUrl, opt => opt.MapFrom(src => src.payurl)) + .ForMember(dest => dest.Urlscheme, opt => opt.MapFrom(src => src.urlscheme)); } } } diff --git a/Apimanager_backend/Config/ServiceCollectionExtensions.cs b/Apimanager_backend/Config/ServiceCollectionExtensions.cs index 8f0a524..5f6c4f3 100644 --- a/Apimanager_backend/Config/ServiceCollectionExtensions.cs +++ b/Apimanager_backend/Config/ServiceCollectionExtensions.cs @@ -1,12 +1,15 @@ using Apimanager_backend.Dtos; using Apimanager_backend.Services; +using Apimanager_backend.Tools; using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; +using Public; using StackExchange.Redis; -using System.ComponentModel; -using System.Runtime.CompilerServices; +using System.Reflection; using System.Text; +using System.Threading.RateLimiting; namespace Apimanager_backend.Config { @@ -22,10 +25,17 @@ namespace Apimanager_backend.Config services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddApiHandler(configuration); + services.AddRateLimit(configuration); return services; } public static IServiceCollection AddJWTService(this IServiceCollection services,IConfiguration configuration) @@ -100,5 +110,76 @@ namespace Apimanager_backend.Config }); return services; } + public static IServiceCollection AddApiHandler(this IServiceCollection services,IConfiguration configuration1) + { + /* + var handlerTypes = Assembly.GetExecutingAssembly() + .GetTypes() + .Where(t => typeof(IBillableApiHandler).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); + + foreach(var type in handlerTypes) + { + services.AddTransient(type); + } + */ + services.AddSingleton(); + var pluginLoaderService = services.BuildServiceProvider() + .GetRequiredService(); + pluginLoaderService.LoadPlugins(services); + + + services.AddScoped(); + return services; + } + public static IServiceCollection AddRateLimit(this IServiceCollection service, IConfiguration configuration1) + { + service.AddRateLimiter(option => + { + option.RejectionStatusCode = 429; + option.OnRejected = async (context, ct) => + { + context.HttpContext.Response.ContentType = "application/json"; + await context.HttpContext.Response.WriteAsJsonAsync(new ResponseBase() + { + Code = 3003, + Data = null, + Message = "API调用已达上限!" + }, ct); + }; + option.AddPolicy("DynamicPerUser", context => + { + // 从前面中间件塞进来的 user 对象 + var dto = context.Items["rateLimit"] as RateLimiterDto; + string partitionKey; + int limit; + + if (dto is null) + { + return RateLimitPartition.GetConcurrencyLimiter("unauthorized", _ => new ConcurrencyLimiterOptions + { + PermitLimit = 0, // 不允许任何请求 + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0 + }); + } + else + { + partitionKey = dto.UserId.ToString(); + limit = dto.RateLimit; + } + + return RateLimitPartition.GetFixedWindowLimiter( + partitionKey, + _ => new FixedWindowRateLimiterOptions + { + PermitLimit = limit, + Window = TimeSpan.FromMinutes(1), + QueueLimit = 0, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst + }); + }); + }); + return service; + } } } diff --git a/Apimanager_backend/Controllers/ApisController.cs b/Apimanager_backend/Controllers/ApisController.cs index 090b8da..56e26db 100644 --- a/Apimanager_backend/Controllers/ApisController.cs +++ b/Apimanager_backend/Controllers/ApisController.cs @@ -47,7 +47,7 @@ namespace Apimanager_backend.Controllers #endregion #region 查询API列表 [HttpGet] - [Authorize(Roles = "User")] + //[Authorize(Roles = "User")] public async Task>>> ApiList(int pageIndex,int pageSize,bool desc) { var list = await apiService.GetApisAsync(pageIndex, pageSize, desc); diff --git a/Apimanager_backend/Controllers/OrderController.cs b/Apimanager_backend/Controllers/OrderController.cs new file mode 100644 index 0000000..593a0d1 --- /dev/null +++ b/Apimanager_backend/Controllers/OrderController.cs @@ -0,0 +1,48 @@ +using Apimanager_backend.Dtos; +using Apimanager_backend.Models; +using Apimanager_backend.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Apimanager_backend.Controllers +{ + [Route("api/[controller][action]")] + [ApiController] + public class OrderController:ControllerBase + { + private IOrderService _orderService; + private ILogger _logger; + public OrderController(IOrderService orderService,ILogger logger) + { + _orderService = orderService; + _logger = logger; + } + //获取全部订单列表 + [HttpGet] + [Authorize(Roles = "Admin")] + public async Task>>> GetOrders(int pageIndex,int pageSize,bool desc) + { + var orderList = await _orderService.GetOrdersAsync(pageIndex,pageSize,desc, null); + var responseData = new ResponseBase>( + code:1000, + message:"Success", + data:orderList + ); + return Ok(responseData); + } + //获取个人订单列表 + [HttpGet] + [Authorize(Roles = "User")] + public async Task>>> GetMyOrders(int pageIndex,int pageSize,bool desc) + { + string userId = User.Claims.First(x => x.Type == "userId").Value; + var orderList = await _orderService.GetOrdersAsync(pageIndex,pageSize,desc,int.Parse(userId)); + var responseData = new ResponseBase>( + code:1000, + data:orderList, + message:"Success" + ); + return Ok(responseData); + } + } +} diff --git a/Apimanager_backend/Controllers/PackageController.cs b/Apimanager_backend/Controllers/PackageController.cs index c46fe35..b3d9aae 100644 --- a/Apimanager_backend/Controllers/PackageController.cs +++ b/Apimanager_backend/Controllers/PackageController.cs @@ -95,7 +95,7 @@ namespace Apimanager_backend.Controllers #endregion #region 获取套餐列表 [HttpGet] - //[Authorize(Roles = "User")] + [Authorize(Roles = "User")] public async Task>>> GetPackageList(int pageIndex,int pageSize,bool desc) { var packageList = await packageService.GetAllPackagesAsync(pageIndex,pageSize,desc); diff --git a/Apimanager_backend/Controllers/PayController.cs b/Apimanager_backend/Controllers/PayController.cs new file mode 100644 index 0000000..bf14a4f --- /dev/null +++ b/Apimanager_backend/Controllers/PayController.cs @@ -0,0 +1,83 @@ +using Apimanager_backend.Dtos; +using Apimanager_backend.Exceptions; +using Apimanager_backend.Models; +using Apimanager_backend.Services; +using Apimanager_backend.Tools; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Apimanager_backend.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class PayController : ControllerBase + { + private ILogger _logger; + private IOrderService _orderService; + private IPaymentConfigService _paymentService; + private IPayService _payService; + public PayController(ILogger logger,IOrderService order,IPaymentConfigService paymentConfigService,IPayService payService) + { + _logger = logger; + _orderService = order; + _paymentService = paymentConfigService; + _payService = payService; + } + [HttpPost] + [Authorize(Roles = "User")] + public async Task CreatePayment([FromBody]CreatePaymentDto dto) + { + var userId = User.Claims.First(x => x.Type == "userId").Value; + //获取支付接口信息 + var paymentConfig = await _paymentService.GetPaymentConfigInfoByTypeAsync(dto.PaymentType.ToString()); + //创建订单 + OrderDto order = new OrderDto(); + order.Amount = dto.Amount; + order.OrderType = OrderType.Purchase; + order.UserId = int.Parse(userId); + order.PaymentType = dto.PaymentType; + Order orderRes = await _orderService.CreateOrderAsync(order); + switch (paymentConfig.PayType) + { + case PayType.None: + throw new BaseException(4001,"当前支付方式未配置"); + case PayType.Epay: + var epayRes = await _payService.CreateEpay(orderRes, paymentConfig,dto.ReturnUrl); + return Ok(epayRes); + default: + throw new BaseException(4001, "不支持的支付方式"); + } + } + [HttpGet] + public async Task Notice( + int pid, string trade_no,string out_trade_no + , string type, string name, decimal money + , string trade_status, string sign, string sign_type + ) + { + Dictionary param = new Dictionary(); + param["pid"] = pid.ToString(); + param["trade_no"] = trade_no; + param["out_trade_no"] = out_trade_no; + param["type"] = type; + param["name"] = name; + param["money"] = money.ToString(); + param["trade_status"] = trade_status; + param["sign"] = sign; + param["sign_type"] = sign_type; + PaymentConfig paymentConfig = await _paymentService.GetPaymentConfigInfoByTypeAsync(type); + bool verifyRes = EpayHelper.VerifySign(param,paymentConfig.SecretKey); + if (!verifyRes) + { + throw new BaseException(4001, "签名校验失败"); + } + OrderDto orderDto = new OrderDto(); + orderDto.ThirdPartyOrderId = trade_no; + if (trade_status == "TRADE_SUCCESS") orderDto.Status = OrderStatus.Completed; + else orderDto.Status = OrderStatus.Failed; + await _orderService.UpdateOrderAsync(orderDto); + return Ok("Success"); + } + } +} diff --git a/Apimanager_backend/Controllers/PublicController.cs b/Apimanager_backend/Controllers/PublicController.cs new file mode 100644 index 0000000..76f387c --- /dev/null +++ b/Apimanager_backend/Controllers/PublicController.cs @@ -0,0 +1,66 @@ +using Apimanager_backend.Dtos; +using Apimanager_backend.Exceptions; +using Apimanager_backend.Services; +using Apimanager_backend.Tools; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; +using Public; +using System.Text.Json; + +namespace Apimanager_backend.Controllers +{ + [Route("api/[controller]/{code}")] + [ApiController] + public class PublicController : ControllerBase + { + private BillableApiDispatcher _dispatcher; + private IApiService _apiService; + private IWebHostEnvironment _webHostEnvironment; + public PublicController(BillableApiDispatcher billableApiDispatcher,IApiService apiService,IWebHostEnvironment webHostEnvironment) + { + _dispatcher = billableApiDispatcher; + _apiService = apiService; + _webHostEnvironment = webHostEnvironment; + } + [HttpGet,HttpDelete,HttpPost,HttpPut] + [EnableRateLimiting("DynamicPerUser")] + public async Task Invoke(string code) + { + var requestMethod = HttpContext.Request.Method; // GET, POST, etc. + + var api = await _apiService.GetApiInfoByEndpointAsync(code); + if (api == null || !api.IsActive) + throw new BaseException(3002,"接口不存在"); + + if (!string.Equals(api.Method.ToString(),requestMethod, StringComparison.OrdinalIgnoreCase)) + throw new BaseException(3002,$"接口不支持{requestMethod}方法"); + + Dictionary parameters = new Dictionary(); + // 获取参数 + if ((requestMethod == "GET" && Request.Query.Count == 0) || (requestMethod == "POST" && Request.ContentLength == 0)) + { + parameters = new Dictionary(); + } + else + { + parameters = requestMethod switch + { + "GET" => HttpContext.Request.Query.ToDictionary(x => x.Key, x => (object)x.Value.ToString()), + _ => await JsonSerializer.DeserializeAsync>(Request.Body) + }; + } + //var userId = int.Parse(User.Claims.First(x => x.Type == "userId").Value); + + var context = new ApiCallContext + { + UserId = -1, + HttpContext = HttpContext, + Parameters = parameters + }; + + var result = await _dispatcher.DispatchAsync(_webHostEnvironment.ContentRootPath,api.Id,api.Endpoint, context); + return Ok(result); + } + } +} diff --git a/Apimanager_backend/Controllers/UploadController.cs b/Apimanager_backend/Controllers/UploadController.cs new file mode 100644 index 0000000..2d5e22b --- /dev/null +++ b/Apimanager_backend/Controllers/UploadController.cs @@ -0,0 +1,236 @@ +using Apimanager_backend.Exceptions; +using Apimanager_backend.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SixLabors.ImageSharp; // 确保添加这个using +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Png; +using Apimanager_backend.Dtos; + +namespace Apimanager_backend.Controllers +{ + [ApiController] + [Route("api/[controller]/[action]")] + public class UploadController:ControllerBase + { + private ILogger _logger; + private readonly IWebHostEnvironment _environment; + private IUserService _userService; + + // 最大文件大小 5MB + private const long MaxFileSize = 5 * 1024 * 1024; + // 允许的文件类型 + private static readonly string[] AllowedExtensions = { ".jpg", ".jpeg", ".png", ".gif" }; + public UploadController(ILogger logger,IWebHostEnvironment webHostEnvironment,IUserService userService) + { + _logger = logger; + _environment = webHostEnvironment; + _userService = userService; + } + [HttpPost] + [Authorize(Roles = "User")] + public async Task UploadPic(IFormFile file) + { + try + { + // 1. 验证文件 + if (file == null || file.Length == 0) + { + throw new BaseException(1001,"缺少文件"); + } + + // 2. 验证文件大小 + if (file.Length > MaxFileSize) + { + throw new BaseException(1001, $"文件大小不能超过{MaxFileSize}"); + } + + var basePath = _environment.WebRootPath ?? _environment.ContentRootPath; + // 3. 验证文件类型 + var extension = Path.GetExtension(file.FileName).ToLowerInvariant(); + if (string.IsNullOrEmpty(extension) || !AllowedExtensions.Contains(extension)) + { + throw new BaseException(1001, "只支持 JPG, PNG, GIF 格式的图片"); + } + + + // 5. 创建存储目录 + var uploadsFolder = Path.Combine(basePath, "uploads", "avatars"); + if (!Directory.Exists(uploadsFolder)) + { + Directory.CreateDirectory(uploadsFolder); + } + var userId = User.Claims.First(x => x.Type == "userId").Value; + + // 6. 生成唯一文件名 + var uniqueFileName = $"{userId}_{DateTime.Now:yyyyMMddHHmmss}{extension}"; + var filePath = Path.Combine(uploadsFolder, uniqueFileName); + + // 7. 处理并保存图片 + using (var image = await Image.LoadAsync(file.OpenReadStream())) + { + // 调整图片大小(最大200x200) + image.Mutate(x => x.Resize(new ResizeOptions + { + Size = new Size(200, 200), + Mode = ResizeMode.Max + })); + + // 保存为高质量JPEG + await image.SaveAsync(filePath); + } + + // 8. 更新数据库中的头像路径 + var avatarUrl = $"/uploads/avatars/{uniqueFileName}"; + var result = await _userService.UpdateUserAvatarAsync(int.Parse(userId), avatarUrl); + + if (!result) + { + // 如果数据库更新失败,删除已上传的文件 + System.IO.File.Delete(filePath); + throw new BaseException(1004,"头像上传失败"); + } + + // 9. 返回成功响应 + return Ok(new ResponseBase(1000,"头像上传成功",null)); + } + catch (Exception ex) + { + _logger.LogError(ex, "头像上传失败"); + throw new BaseException(1004, "头像上传失败"); + } + } + [HttpPost] + [Authorize(Roles = "Admin")] + public async Task UploadLogo(IFormFile file) + { + try + { + // 1. 验证文件 + if (file == null || file.Length == 0) + { + throw new BaseException(1001, "缺少文件"); + } + + // 2. 验证文件大小 + if (file.Length > MaxFileSize) + { + throw new BaseException(1001, $"文件大小不能超过{MaxFileSize}"); + } + + var basePath = _environment.WebRootPath ?? _environment.ContentRootPath; + // 3. 验证文件类型 + var extension = Path.GetExtension(file.FileName).ToLowerInvariant(); + if (string.IsNullOrEmpty(extension) || !AllowedExtensions.Contains(extension)) + { + throw new BaseException(1001, "只支持 JPG, PNG, GIF 格式的图片"); + } + + + // 5. 创建存储目录 + var uploadsFolder = Path.Combine(basePath); + var filePath = Path.Combine(uploadsFolder, "logo.png"); + + // 7. 处理并保存图片 + using (var image = await Image.LoadAsync(file.OpenReadStream())) + { + // 调整图片大小(最大200x200) + /* + image.Mutate(x => x.Resize(new ResizeOptions + { + Size = new Size(200, 200), + Mode = ResizeMode.Max + })); + + */ + // 强制保存为PNG(高质量) + await image.SaveAsync(filePath, new PngEncoder + { + CompressionLevel = PngCompressionLevel.BestCompression // 最佳压缩 + }); + } + + // 9. 返回成功响应 + return Ok(new ResponseBase(1000, "LOGO上传成功", null)); + } + catch (Exception ex) + { + _logger.LogError(ex, "LOGO上传失败"); + throw new BaseException(1004, "LOGO上传失败"); + } + } + [HttpPost] + [Authorize(Roles = "Admin")] + public async Task UploadFavicon(IFormFile file) + { + try + { + // 1. 验证文件 + if (file == null || file.Length == 0) + { + throw new BaseException(1001, "缺少文件"); + } + + // 2. 验证文件大小 + if (file.Length > MaxFileSize) + { + throw new BaseException(1001, $"文件大小不能超过{MaxFileSize}"); + } + + var basePath = _environment.WebRootPath ?? _environment.ContentRootPath; + // 3. 验证文件类型 + var extension = Path.GetExtension(file.FileName).ToLowerInvariant(); + if (string.IsNullOrEmpty(extension) || extension != ".ico") + { + throw new BaseException(1001, "只支持 ICO 格式的图片"); + } + + + // 3. 保存到网站根目录 + var icoPath = Path.Combine(_environment.WebRootPath, "favicon.ico"); + using (var stream = new FileStream(icoPath, FileMode.Create)) + { + await file.CopyToAsync(stream); + } + + + // 9. 返回成功响应 + return Ok(new ResponseBase(1000, "favicon上传成功", null)); + } + catch (Exception ex) + { + _logger.LogError(ex, "Favicon上传失败"); + throw new BaseException(1004, "Favicon上传失败"); + } + } + [HttpPost] + [Authorize(Roles = "Admin")] + public async Task UploadApi(IFormFile file) + { + if (file == null || file.Length == 0) + throw new BaseException(1001,"请上传文件"); + + // 检查扩展名 + var ext = Path.GetExtension(file.FileName); + if (ext != ".dll") + throw new BaseException(1001, "只允许上传DLL"); + + // 插件保存路径 + var saveDir = Path.Combine(_environment.ContentRootPath, "ApiHandler"); + if (!Directory.Exists(saveDir)) + Directory.CreateDirectory(saveDir); + + var filePath = Path.Combine(saveDir, file.FileName); + + // 保存文件 + using (var stream = new FileStream(filePath, FileMode.Create)) + { + await file.CopyToAsync(stream); + } + + return Ok(new ResponseBase(1000,"上传成功",null)); + } + + } +} diff --git a/Apimanager_backend/Controllers/UserController.cs b/Apimanager_backend/Controllers/UserController.cs index d6ce368..fd2b5e9 100644 --- a/Apimanager_backend/Controllers/UserController.cs +++ b/Apimanager_backend/Controllers/UserController.cs @@ -78,7 +78,7 @@ namespace Apimanager_backend.Controllers [Authorize(Roles = "User")] public async Task>> Update([FromBody]UpdateUserDto dto) { - var userId = User.Claims.First(x => x.ValueType == "userId").Value; + var userId = User.Claims.First(x => x.Type == "userId").Value; var userInfo = await userService.UpdateUserAsync(int.Parse(userId),dto); var res = new ResponseBase( code:1000, diff --git a/Apimanager_backend/Data/ApiConfig.cs b/Apimanager_backend/Data/ApiConfig.cs index cf36445..8fec5f2 100644 --- a/Apimanager_backend/Data/ApiConfig.cs +++ b/Apimanager_backend/Data/ApiConfig.cs @@ -13,6 +13,9 @@ namespace Apimanager_backend.Data //自增 builder.Property(x => x.Id) .ValueGeneratedOnAdd(); + //设置唯一 + builder.HasIndex(x => x.Endpoint) + .IsUnique(); //外键 builder.HasOne(x => x.Package) .WithMany(u => u.Apis) diff --git a/Apimanager_backend/Data/ApiContext.cs b/Apimanager_backend/Data/ApiContext.cs index 9c5c8c5..8d83950 100644 --- a/Apimanager_backend/Data/ApiContext.cs +++ b/Apimanager_backend/Data/ApiContext.cs @@ -18,6 +18,10 @@ namespace Apimanager_backend.Data public DbSet OperationLogs { get; set; } //订单表 public DbSet Orders { get; set; } + + //API套餐关联表 + public DbSet apiPackageItems { get; set; } + //用户已订购套餐表 public DbSet UserPackages { get; set; } //用户角色表 @@ -26,14 +30,20 @@ namespace Apimanager_backend.Data public DbSet Logs { get; set; } //系统配置表 public DbSet SystemConfigs { get; set; } + + //支付配置 + public DbSet paymentConfigs { get; set; } public ApiContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApiContext).Assembly); // 配置全局查询筛选器 modelBuilder.Entity().HasQueryFilter(u => !u.IsDelete); + modelBuilder.Entity() + .HasQueryFilter(ur => !ur.User.IsDelete); modelBuilder.Entity().HasQueryFilter(a => !a.IsDelete); modelBuilder.Entity().HasQueryFilter(x => !x.IsDeleted); + modelBuilder.Entity().HasQueryFilter(x => !x.IsDeleted); //配置日志表 modelBuilder.Entity().HasKey(x => x.Id); modelBuilder.Entity() diff --git a/Apimanager_backend/Data/ApiPackageItemConfig.cs b/Apimanager_backend/Data/ApiPackageItemConfig.cs new file mode 100644 index 0000000..39cd26b --- /dev/null +++ b/Apimanager_backend/Data/ApiPackageItemConfig.cs @@ -0,0 +1,26 @@ +using Apimanager_backend.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Apimanager_backend.Data +{ + public class ApiPackageItemConfig : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + //主键 + builder.HasKey(x => x.Id); + //自增 + builder.Property(x => x.Id) + .ValueGeneratedOnAdd(); + //外键 + builder.HasOne(x => x.Api) + .WithMany(u => u.ApiPackageItems) + .HasForeignKey(x => x.ApiId); + + builder.HasOne(x => x.ApiPackage) + .WithMany(u => u.ApiPackageItems) + .HasForeignKey(x => x.ApiPackageId); + } + } +} diff --git a/Apimanager_backend/Data/PaymentConfigConfig.cs b/Apimanager_backend/Data/PaymentConfigConfig.cs new file mode 100644 index 0000000..b11a1cb --- /dev/null +++ b/Apimanager_backend/Data/PaymentConfigConfig.cs @@ -0,0 +1,22 @@ +using Apimanager_backend.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Apimanager_backend.Data +{ + public class PaymentConfigConfig : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.Property(x => x.Id) + .ValueGeneratedOnAdd(); + builder.HasData( + new PaymentConfig() { Id = 1, Method = PaymentType.AliPay,PayType = PayType.Official, AppId = "", SecretKey = "", PublicKey = "", NotifyUrl = "", GatewayUrl = "", IsEnabled = false }, + new PaymentConfig() { Id = 2, Method = PaymentType.WxPay, PayType = PayType.Official, AppId = "", SecretKey = "", PublicKey = "", NotifyUrl = "", GatewayUrl = "", IsEnabled = false }, + new PaymentConfig() { Id = 3, Method = PaymentType.QQPay, PayType = PayType.Official, AppId = "", SecretKey = "", PublicKey = "", NotifyUrl = "", GatewayUrl = "", IsEnabled = false }, + new PaymentConfig() { Id = 4, Method = PaymentType.Bank, PayType = PayType.Official, AppId = "", SecretKey = "", PublicKey = "", NotifyUrl = "", GatewayUrl = "", IsEnabled = false } + ); + } + } +} diff --git a/Apimanager_backend/Data/PluginLoadContext.cs b/Apimanager_backend/Data/PluginLoadContext.cs new file mode 100644 index 0000000..da1053d --- /dev/null +++ b/Apimanager_backend/Data/PluginLoadContext.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.Loader; + +namespace Apimanager_backend.Data +{ + // 隔离加载上下文 + public class PluginLoadContext : AssemblyLoadContext + { + private readonly AssemblyDependencyResolver _resolver; + + public PluginLoadContext(string pluginPath) : base(isCollectible: true) + { + _resolver = new AssemblyDependencyResolver(pluginPath); + } + + protected override Assembly Load(AssemblyName assemblyName) + { + // 避免重复加载核心库 + if (assemblyName.Name == "YourSharedContract") + return null; + + string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); + return assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) : null; + } + } +} diff --git a/Apimanager_backend/Dtos/CreatePaymentDto.cs b/Apimanager_backend/Dtos/CreatePaymentDto.cs new file mode 100644 index 0000000..6ee7b4d --- /dev/null +++ b/Apimanager_backend/Dtos/CreatePaymentDto.cs @@ -0,0 +1,13 @@ +using Apimanager_backend.Models; +using System.ComponentModel.DataAnnotations; + +namespace Apimanager_backend.Dtos +{ + public class CreatePaymentDto + { + public PaymentType PaymentType { get; set; } + [Required] + public decimal Amount { get; set; } + public string ReturnUrl { get; set; } + } +} diff --git a/Apimanager_backend/Dtos/EpayResponse.cs b/Apimanager_backend/Dtos/EpayResponse.cs new file mode 100644 index 0000000..23068a3 --- /dev/null +++ b/Apimanager_backend/Dtos/EpayResponse.cs @@ -0,0 +1,12 @@ +namespace Apimanager_backend.Dtos +{ + public class EpayResponse + { + public int code { get; set; } + public string msg { get; set; } + public string trade_no { get; set; } + public string? payurl { get; set; } + public string? qrcode { get; set; } + public string? urlscheme { get; set; } + } +} diff --git a/Apimanager_backend/Dtos/OrderDto.cs b/Apimanager_backend/Dtos/OrderDto.cs new file mode 100644 index 0000000..08484fb --- /dev/null +++ b/Apimanager_backend/Dtos/OrderDto.cs @@ -0,0 +1,45 @@ +using Apimanager_backend.Models; +using System.ComponentModel.DataAnnotations; + +namespace Apimanager_backend.Dtos +{ + public class OrderDto + { + + /// + /// 外键,用户ID + /// + public int UserId { get; set; } + + /// + /// 订单号,唯一 + /// + public string? OrderNumber { get; set; } // varchar(50) + + /// + /// 第三方系统订单编号 + /// + public string? ThirdPartyOrderId { get; set; } // varchar(100) + + /// + /// 订单金额 + /// + public decimal Amount { get; set; } // decimal(10, 2) + + //支付方式 + public PaymentType PaymentType { get; set; } + + /// + /// 订单类型 + /// + public OrderType OrderType { get; set; } // enum('Recharge','Purchase','Refund') + + + /// + /// 订单描述,可选的详细信息 + /// + public string? Description { get; set; } // varchar(255) + + public OrderStatus Status { get; set; } + } +} diff --git a/Apimanager_backend/Dtos/PayReturnData.cs b/Apimanager_backend/Dtos/PayReturnData.cs new file mode 100644 index 0000000..5a28b46 --- /dev/null +++ b/Apimanager_backend/Dtos/PayReturnData.cs @@ -0,0 +1,11 @@ +namespace Apimanager_backend.Dtos +{ + public class PayReturnData + { + public bool Success { get; set; } + public string? OrderNum { get; set; } + public string? PayUrl { get; set; } + public string? QrCode { get; set; } + public string? Urlscheme { get; set; } + } +} diff --git a/Apimanager_backend/Dtos/RateLimiterDto.cs b/Apimanager_backend/Dtos/RateLimiterDto.cs new file mode 100644 index 0000000..14d1724 --- /dev/null +++ b/Apimanager_backend/Dtos/RateLimiterDto.cs @@ -0,0 +1,8 @@ +namespace Apimanager_backend.Dtos +{ + public class RateLimiterDto + { + public int UserId { get; set; } + public int RateLimit { get; set; } + } +} diff --git a/Apimanager_backend/Dtos/UserInfoDto.cs b/Apimanager_backend/Dtos/UserInfoDto.cs index afe3cca..88f5b80 100644 --- a/Apimanager_backend/Dtos/UserInfoDto.cs +++ b/Apimanager_backend/Dtos/UserInfoDto.cs @@ -7,9 +7,10 @@ namespace Apimanager_backend.Dtos public int Id { get; set; } public string UserName { get; set; } public string Email { get; set; } - public List Roles { get; set; } + public List? Roles { get; set; } public bool IsBan { get; set; } public decimal Balance { get; set; } public DateTime Created { get; set; } + public List? Packages { get; set; } } } diff --git a/Apimanager_backend/Migrations/20250728124413_add_order_isdeleted.Designer.cs b/Apimanager_backend/Migrations/20250728124413_add_order_isdeleted.Designer.cs new file mode 100644 index 0000000..6caccc1 --- /dev/null +++ b/Apimanager_backend/Migrations/20250728124413_add_order_isdeleted.Designer.cs @@ -0,0 +1,575 @@ +// +using System; +using Apimanager_backend.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20250728124413_add_order_isdeleted")] + partial class add_order_isdeleted + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Endpoint") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("IsThirdParty") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.ToTable("Apis"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("CallResult") + .HasColumnType("int"); + + b.Property("CallTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("UserId"); + + b.ToTable("CallLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("Request") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Response") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ResponseType") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.ToTable("ApiRequestExample"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CallLimit") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("OneMinuteLimit") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("decimal(65,30)"); + + b.HasKey("Id"); + + b.ToTable("Apipackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Log", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Exception") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LogLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MessageTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("Logs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("varchar(45)"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.Property("TargetType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("UserAgent") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("OperationLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("OrderNumber") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("OrderType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ThirdPartyOrderId") + .HasColumnType("varchar(255)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OrderNumber") + .IsUnique(); + + b.HasIndex("ThirdPartyOrderId") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigBody") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ConfigName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SystemConfigs"); + + b.HasData( + new + { + Id = 1, + ConfigBody = "青蓝", + ConfigName = "SystemName" + }, + new + { + Id = 2, + ConfigBody = "描述", + ConfigName = "SystemDescription" + }, + new + { + Id = 3, + ConfigBody = "", + ConfigName = "LogoLocation" + }, + new + { + Id = 4, + ConfigBody = "", + ConfigName = "FaviconLocation" + }, + new + { + Id = 5, + ConfigBody = "13000000000", + ConfigName = "Phone" + }, + new + { + Id = 6, + ConfigBody = "admin@admin.com", + ConfigName = "Email" + }, + new + { + Id = 7, + ConfigBody = "{\"RegisterOn\":true,\"Emailvalidate\":true}", + ConfigName = "RegisterConfig" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .HasColumnType("longtext"); + + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsBan") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("PassHash") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasData( + new + { + Id = -1, + Balance = 0m, + CreatedAt = new DateTime(2025, 7, 28, 12, 44, 13, 79, DateTimeKind.Utc).AddTicks(8845), + Email = "admin1@admin.com", + IsBan = false, + IsDelete = false, + PassHash = "e10adc3949ba59abbe56e057f20f883e", + Username = "admin" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.Property("PurchasedAt") + .HasColumnType("datetime(6)"); + + b.Property("RemainingCalls") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Role") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Apis") + .HasForeignKey("PackageId"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiCalls") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("CallLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiRequestExamples") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("operationLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Orders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Packages") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Packages") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Navigation("ApiCalls"); + + b.Navigation("ApiRequestExamples"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Navigation("Apis"); + + b.Navigation("Packages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Navigation("CallLogs"); + + b.Navigation("Orders"); + + b.Navigation("Packages"); + + b.Navigation("Roles"); + + b.Navigation("operationLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apimanager_backend/Migrations/20250728124413_add_order_isdeleted.cs b/Apimanager_backend/Migrations/20250728124413_add_order_isdeleted.cs new file mode 100644 index 0000000..dae4b8d --- /dev/null +++ b/Apimanager_backend/Migrations/20250728124413_add_order_isdeleted.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + /// + public partial class add_order_isdeleted : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsDeleted", + table: "Orders", + type: "tinyint(1)", + nullable: false, + defaultValue: false); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 28, 12, 44, 13, 79, DateTimeKind.Utc).AddTicks(8845)); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsDeleted", + table: "Orders"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2024, 11, 10, 13, 48, 10, 873, DateTimeKind.Utc).AddTicks(7811)); + } + } +} diff --git a/Apimanager_backend/Migrations/20250729080100_add_PaymentConfig.Designer.cs b/Apimanager_backend/Migrations/20250729080100_add_PaymentConfig.Designer.cs new file mode 100644 index 0000000..9c48065 --- /dev/null +++ b/Apimanager_backend/Migrations/20250729080100_add_PaymentConfig.Designer.cs @@ -0,0 +1,676 @@ +// +using System; +using Apimanager_backend.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20250729080100_add_PaymentConfig")] + partial class add_PaymentConfig + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Endpoint") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("IsThirdParty") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.ToTable("Apis"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("CallResult") + .HasColumnType("int"); + + b.Property("CallTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("UserId"); + + b.ToTable("CallLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("Request") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Response") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ResponseType") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.ToTable("ApiRequestExample"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CallLimit") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("OneMinuteLimit") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("decimal(65,30)"); + + b.HasKey("Id"); + + b.ToTable("Apipackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Log", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Exception") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LogLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MessageTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("Logs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("varchar(45)"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.Property("TargetType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("UserAgent") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("OperationLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("OrderNumber") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("OrderType") + .HasColumnType("int"); + + b.Property("PaiAt") + .HasColumnType("datetime(6)"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ThirdPartyOrderId") + .HasColumnType("varchar(255)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OrderNumber") + .IsUnique(); + + b.HasIndex("ThirdPartyOrderId") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.PaymentConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ExtraSettingsJson") + .HasColumnType("longtext"); + + b.Property("GatewayUrl") + .HasColumnType("longtext"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("NotifyUrl") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("SecretKey") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfig"); + + b.HasData( + new + { + Id = 1, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 0, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 2, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 1, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 3, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 3, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 4, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 2, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 5, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 4, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigBody") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ConfigName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SystemConfigs"); + + b.HasData( + new + { + Id = 1, + ConfigBody = "青蓝", + ConfigName = "SystemName" + }, + new + { + Id = 2, + ConfigBody = "描述", + ConfigName = "SystemDescription" + }, + new + { + Id = 3, + ConfigBody = "", + ConfigName = "LogoLocation" + }, + new + { + Id = 4, + ConfigBody = "", + ConfigName = "FaviconLocation" + }, + new + { + Id = 5, + ConfigBody = "13000000000", + ConfigName = "Phone" + }, + new + { + Id = 6, + ConfigBody = "admin@admin.com", + ConfigName = "Email" + }, + new + { + Id = 7, + ConfigBody = "{\"RegisterOn\":true,\"Emailvalidate\":true}", + ConfigName = "RegisterConfig" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .HasColumnType("longtext"); + + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsBan") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("PassHash") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasData( + new + { + Id = -1, + Balance = 0m, + CreatedAt = new DateTime(2025, 7, 29, 8, 1, 0, 284, DateTimeKind.Utc).AddTicks(4585), + Email = "admin1@admin.com", + IsBan = false, + IsDelete = false, + PassHash = "e10adc3949ba59abbe56e057f20f883e", + Username = "admin" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.Property("PurchasedAt") + .HasColumnType("datetime(6)"); + + b.Property("RemainingCalls") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Role") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Apis") + .HasForeignKey("PackageId"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiCalls") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("CallLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiRequestExamples") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("operationLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Orders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Packages") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Packages") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Navigation("ApiCalls"); + + b.Navigation("ApiRequestExamples"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Navigation("Apis"); + + b.Navigation("Packages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Navigation("CallLogs"); + + b.Navigation("Orders"); + + b.Navigation("Packages"); + + b.Navigation("Roles"); + + b.Navigation("operationLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apimanager_backend/Migrations/20250729080100_add_PaymentConfig.cs b/Apimanager_backend/Migrations/20250729080100_add_PaymentConfig.cs new file mode 100644 index 0000000..14aec4f --- /dev/null +++ b/Apimanager_backend/Migrations/20250729080100_add_PaymentConfig.cs @@ -0,0 +1,119 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace Apimanager_backend.Migrations +{ + /// + public partial class add_PaymentConfig : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "UpdatedAt", + table: "Orders", + type: "datetime(6)", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "datetime(6)"); + + migrationBuilder.AddColumn( + name: "PaiAt", + table: "Orders", + type: "datetime(6)", + nullable: true); + + migrationBuilder.AddColumn( + name: "PaymentType", + table: "Orders", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "PaymentConfig", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Method = table.Column(type: "int", nullable: false), + AppId = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + SecretKey = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + PublicKey = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + NotifyUrl = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + GatewayUrl = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + IsEnabled = table.Column(type: "tinyint(1)", nullable: false), + ExtraSettingsJson = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_PaymentConfig", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.InsertData( + table: "PaymentConfig", + columns: new[] { "Id", "AppId", "Description", "ExtraSettingsJson", "GatewayUrl", "IsEnabled", "Method", "NotifyUrl", "PublicKey", "SecretKey" }, + values: new object[,] + { + { 1, "", null, null, "", false, 0, "", "", "" }, + { 2, "", null, null, "", false, 1, "", "", "" }, + { 3, "", null, null, "", false, 3, "", "", "" }, + { 4, "", null, null, "", false, 2, "", "", "" }, + { 5, "", null, null, "", false, 4, "", "", "" } + }); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 29, 8, 1, 0, 284, DateTimeKind.Utc).AddTicks(4585)); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PaymentConfig"); + + migrationBuilder.DropColumn( + name: "PaiAt", + table: "Orders"); + + migrationBuilder.DropColumn( + name: "PaymentType", + table: "Orders"); + + migrationBuilder.AlterColumn( + name: "UpdatedAt", + table: "Orders", + type: "datetime(6)", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + oldClrType: typeof(DateTime), + oldType: "datetime(6)", + oldNullable: true); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 28, 12, 44, 13, 79, DateTimeKind.Utc).AddTicks(8845)); + } + } +} diff --git a/Apimanager_backend/Migrations/20250729102235_add_apipackageItem.Designer.cs b/Apimanager_backend/Migrations/20250729102235_add_apipackageItem.Designer.cs new file mode 100644 index 0000000..b7639cf --- /dev/null +++ b/Apimanager_backend/Migrations/20250729102235_add_apipackageItem.Designer.cs @@ -0,0 +1,720 @@ +// +using System; +using Apimanager_backend.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20250729102235_add_apipackageItem")] + partial class add_apipackageItem + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Endpoint") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("IsThirdParty") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.ToTable("Apis"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("CallResult") + .HasColumnType("int"); + + b.Property("CallTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("UserId"); + + b.ToTable("CallLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("ApiPackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("ApiPackageId"); + + b.ToTable("ApiPackageItem"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("Request") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Response") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ResponseType") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.ToTable("ApiRequestExample"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CallLimit") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("OneMinuteLimit") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("decimal(65,30)"); + + b.HasKey("Id"); + + b.ToTable("Apipackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Log", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Exception") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LogLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MessageTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("Logs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("varchar(45)"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.Property("TargetType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("UserAgent") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("OperationLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("OrderNumber") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("OrderType") + .HasColumnType("int"); + + b.Property("PaiAt") + .HasColumnType("datetime(6)"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ThirdPartyOrderId") + .HasColumnType("varchar(255)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OrderNumber") + .IsUnique(); + + b.HasIndex("ThirdPartyOrderId") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.PaymentConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ExtraSettingsJson") + .HasColumnType("longtext"); + + b.Property("GatewayUrl") + .HasColumnType("longtext"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("NotifyUrl") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("SecretKey") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfig"); + + b.HasData( + new + { + Id = 1, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 0, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 2, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 1, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 3, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 3, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 4, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 2, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 5, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 4, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigBody") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ConfigName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SystemConfigs"); + + b.HasData( + new + { + Id = 1, + ConfigBody = "青蓝", + ConfigName = "SystemName" + }, + new + { + Id = 2, + ConfigBody = "描述", + ConfigName = "SystemDescription" + }, + new + { + Id = 3, + ConfigBody = "", + ConfigName = "LogoLocation" + }, + new + { + Id = 4, + ConfigBody = "", + ConfigName = "FaviconLocation" + }, + new + { + Id = 5, + ConfigBody = "13000000000", + ConfigName = "Phone" + }, + new + { + Id = 6, + ConfigBody = "admin@admin.com", + ConfigName = "Email" + }, + new + { + Id = 7, + ConfigBody = "{\"RegisterOn\":true,\"Emailvalidate\":true}", + ConfigName = "RegisterConfig" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .HasColumnType("longtext"); + + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsBan") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("PassHash") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasData( + new + { + Id = -1, + Balance = 0m, + CreatedAt = new DateTime(2025, 7, 29, 10, 22, 34, 333, DateTimeKind.Utc).AddTicks(3700), + Email = "admin1@admin.com", + IsBan = false, + IsDelete = false, + PassHash = "e10adc3949ba59abbe56e057f20f883e", + Username = "admin" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.Property("PurchasedAt") + .HasColumnType("datetime(6)"); + + b.Property("RemainingCalls") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Role") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Apis") + .HasForeignKey("PackageId"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiCalls") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("CallLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.Apipackage", "ApiPackage") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiPackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("ApiPackage"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiRequestExamples") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("operationLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Orders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Packages") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Packages") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Navigation("ApiCalls"); + + b.Navigation("ApiPackageItems"); + + b.Navigation("ApiRequestExamples"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Navigation("ApiPackageItems"); + + b.Navigation("Apis"); + + b.Navigation("Packages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Navigation("CallLogs"); + + b.Navigation("Orders"); + + b.Navigation("Packages"); + + b.Navigation("Roles"); + + b.Navigation("operationLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apimanager_backend/Migrations/20250729102235_add_apipackageItem.cs b/Apimanager_backend/Migrations/20250729102235_add_apipackageItem.cs new file mode 100644 index 0000000..774b0d5 --- /dev/null +++ b/Apimanager_backend/Migrations/20250729102235_add_apipackageItem.cs @@ -0,0 +1,74 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + /// + public partial class add_apipackageItem : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ApiPackageItem", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + ApiPackageId = table.Column(type: "int", nullable: false), + ApiId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiPackageItem", x => x.Id); + table.ForeignKey( + name: "FK_ApiPackageItem_Apipackages_ApiPackageId", + column: x => x.ApiPackageId, + principalTable: "Apipackages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ApiPackageItem_Apis_ApiId", + column: x => x.ApiId, + principalTable: "Apis", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 29, 10, 22, 34, 333, DateTimeKind.Utc).AddTicks(3700)); + + migrationBuilder.CreateIndex( + name: "IX_ApiPackageItem_ApiId", + table: "ApiPackageItem", + column: "ApiId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiPackageItem_ApiPackageId", + table: "ApiPackageItem", + column: "ApiPackageId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ApiPackageItem"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 29, 8, 1, 0, 284, DateTimeKind.Utc).AddTicks(4585)); + } + } +} diff --git a/Apimanager_backend/Migrations/20250730145807_update_api_Endpoint.Designer.cs b/Apimanager_backend/Migrations/20250730145807_update_api_Endpoint.Designer.cs new file mode 100644 index 0000000..a8b1591 --- /dev/null +++ b/Apimanager_backend/Migrations/20250730145807_update_api_Endpoint.Designer.cs @@ -0,0 +1,723 @@ +// +using System; +using Apimanager_backend.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20250730145807_update_api_Endpoint")] + partial class update_api_Endpoint + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Endpoint") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("IsThirdParty") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Endpoint") + .IsUnique(); + + b.HasIndex("PackageId"); + + b.ToTable("Apis"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("CallResult") + .HasColumnType("int"); + + b.Property("CallTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("UserId"); + + b.ToTable("CallLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("ApiPackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("ApiPackageId"); + + b.ToTable("ApiPackageItem"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("Request") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Response") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ResponseType") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.ToTable("ApiRequestExample"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CallLimit") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("OneMinuteLimit") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("decimal(65,30)"); + + b.HasKey("Id"); + + b.ToTable("Apipackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Log", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Exception") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LogLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MessageTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("Logs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("varchar(45)"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.Property("TargetType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("UserAgent") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("OperationLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("OrderNumber") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("OrderType") + .HasColumnType("int"); + + b.Property("PaiAt") + .HasColumnType("datetime(6)"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ThirdPartyOrderId") + .HasColumnType("varchar(255)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OrderNumber") + .IsUnique(); + + b.HasIndex("ThirdPartyOrderId") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.PaymentConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ExtraSettingsJson") + .HasColumnType("longtext"); + + b.Property("GatewayUrl") + .HasColumnType("longtext"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("NotifyUrl") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("SecretKey") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfig"); + + b.HasData( + new + { + Id = 1, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 0, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 2, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 1, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 3, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 3, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 4, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 2, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 5, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 4, + NotifyUrl = "", + PublicKey = "", + SecretKey = "" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigBody") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ConfigName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SystemConfigs"); + + b.HasData( + new + { + Id = 1, + ConfigBody = "青蓝", + ConfigName = "SystemName" + }, + new + { + Id = 2, + ConfigBody = "描述", + ConfigName = "SystemDescription" + }, + new + { + Id = 3, + ConfigBody = "", + ConfigName = "LogoLocation" + }, + new + { + Id = 4, + ConfigBody = "", + ConfigName = "FaviconLocation" + }, + new + { + Id = 5, + ConfigBody = "13000000000", + ConfigName = "Phone" + }, + new + { + Id = 6, + ConfigBody = "admin@admin.com", + ConfigName = "Email" + }, + new + { + Id = 7, + ConfigBody = "{\"RegisterOn\":true,\"Emailvalidate\":true}", + ConfigName = "RegisterConfig" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .HasColumnType("longtext"); + + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsBan") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("PassHash") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasData( + new + { + Id = -1, + Balance = 0m, + CreatedAt = new DateTime(2025, 7, 30, 14, 58, 7, 232, DateTimeKind.Utc).AddTicks(4921), + Email = "admin1@admin.com", + IsBan = false, + IsDelete = false, + PassHash = "e10adc3949ba59abbe56e057f20f883e", + Username = "admin" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.Property("PurchasedAt") + .HasColumnType("datetime(6)"); + + b.Property("RemainingCalls") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Role") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Apis") + .HasForeignKey("PackageId"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiCalls") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("CallLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.Apipackage", "ApiPackage") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiPackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("ApiPackage"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiRequestExamples") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("operationLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Orders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Packages") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Packages") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Navigation("ApiCalls"); + + b.Navigation("ApiPackageItems"); + + b.Navigation("ApiRequestExamples"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Navigation("ApiPackageItems"); + + b.Navigation("Apis"); + + b.Navigation("Packages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Navigation("CallLogs"); + + b.Navigation("Orders"); + + b.Navigation("Packages"); + + b.Navigation("Roles"); + + b.Navigation("operationLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apimanager_backend/Migrations/20250730145807_update_api_Endpoint.cs b/Apimanager_backend/Migrations/20250730145807_update_api_Endpoint.cs new file mode 100644 index 0000000..921708c --- /dev/null +++ b/Apimanager_backend/Migrations/20250730145807_update_api_Endpoint.cs @@ -0,0 +1,63 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + /// + public partial class update_api_Endpoint : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Endpoint", + table: "Apis", + type: "varchar(255)", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 30, 14, 58, 7, 232, DateTimeKind.Utc).AddTicks(4921)); + + migrationBuilder.CreateIndex( + name: "IX_Apis_Endpoint", + table: "Apis", + column: "Endpoint", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Apis_Endpoint", + table: "Apis"); + + migrationBuilder.AlterColumn( + name: "Endpoint", + table: "Apis", + type: "longtext", + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(255)") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 29, 10, 22, 34, 333, DateTimeKind.Utc).AddTicks(3700)); + } + } +} diff --git a/Apimanager_backend/Migrations/20250731061032_update_paymentconfig.Designer.cs b/Apimanager_backend/Migrations/20250731061032_update_paymentconfig.Designer.cs new file mode 100644 index 0000000..d4579ac --- /dev/null +++ b/Apimanager_backend/Migrations/20250731061032_update_paymentconfig.Designer.cs @@ -0,0 +1,719 @@ +// +using System; +using Apimanager_backend.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20250731061032_update_paymentconfig")] + partial class update_paymentconfig + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Endpoint") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("IsThirdParty") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Endpoint") + .IsUnique(); + + b.HasIndex("PackageId"); + + b.ToTable("Apis"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("CallResult") + .HasColumnType("int"); + + b.Property("CallTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("UserId"); + + b.ToTable("CallLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("ApiPackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("ApiPackageId"); + + b.ToTable("ApiPackageItem"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("Request") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Response") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ResponseType") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.ToTable("ApiRequestExample"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CallLimit") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("OneMinuteLimit") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("decimal(65,30)"); + + b.HasKey("Id"); + + b.ToTable("Apipackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Log", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Exception") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LogLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MessageTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("Logs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("varchar(45)"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.Property("TargetType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("UserAgent") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("OperationLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("OrderNumber") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("OrderType") + .HasColumnType("int"); + + b.Property("PaiAt") + .HasColumnType("datetime(6)"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ThirdPartyOrderId") + .HasColumnType("varchar(255)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OrderNumber") + .IsUnique(); + + b.HasIndex("ThirdPartyOrderId") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.PaymentConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ExtraSettingsJson") + .HasColumnType("longtext"); + + b.Property("GatewayUrl") + .HasColumnType("longtext"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("NotifyUrl") + .HasColumnType("longtext"); + + b.Property("PayType") + .HasColumnType("int"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("SecretKey") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("PaymentConfig"); + + b.HasData( + new + { + Id = 1, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 0, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 2, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 1, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 3, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 3, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 4, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 2, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigBody") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ConfigName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SystemConfigs"); + + b.HasData( + new + { + Id = 1, + ConfigBody = "青蓝", + ConfigName = "SystemName" + }, + new + { + Id = 2, + ConfigBody = "描述", + ConfigName = "SystemDescription" + }, + new + { + Id = 3, + ConfigBody = "", + ConfigName = "LogoLocation" + }, + new + { + Id = 4, + ConfigBody = "", + ConfigName = "FaviconLocation" + }, + new + { + Id = 5, + ConfigBody = "13000000000", + ConfigName = "Phone" + }, + new + { + Id = 6, + ConfigBody = "admin@admin.com", + ConfigName = "Email" + }, + new + { + Id = 7, + ConfigBody = "{\"RegisterOn\":true,\"Emailvalidate\":true}", + ConfigName = "RegisterConfig" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .HasColumnType("longtext"); + + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsBan") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("PassHash") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasData( + new + { + Id = -1, + Balance = 0m, + CreatedAt = new DateTime(2025, 7, 31, 6, 10, 31, 712, DateTimeKind.Utc).AddTicks(1486), + Email = "admin1@admin.com", + IsBan = false, + IsDelete = false, + PassHash = "e10adc3949ba59abbe56e057f20f883e", + Username = "admin" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.Property("PurchasedAt") + .HasColumnType("datetime(6)"); + + b.Property("RemainingCalls") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Role") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Apis") + .HasForeignKey("PackageId"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiCalls") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("CallLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.Apipackage", "ApiPackage") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiPackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("ApiPackage"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiRequestExamples") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("operationLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Orders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Packages") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Packages") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Navigation("ApiCalls"); + + b.Navigation("ApiPackageItems"); + + b.Navigation("ApiRequestExamples"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Navigation("ApiPackageItems"); + + b.Navigation("Apis"); + + b.Navigation("Packages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Navigation("CallLogs"); + + b.Navigation("Orders"); + + b.Navigation("Packages"); + + b.Navigation("Roles"); + + b.Navigation("operationLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apimanager_backend/Migrations/20250731061032_update_paymentconfig.cs b/Apimanager_backend/Migrations/20250731061032_update_paymentconfig.cs new file mode 100644 index 0000000..a1ad8db --- /dev/null +++ b/Apimanager_backend/Migrations/20250731061032_update_paymentconfig.cs @@ -0,0 +1,82 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + /// + public partial class update_paymentconfig : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "PaymentConfig", + keyColumn: "Id", + keyValue: 5); + + migrationBuilder.AddColumn( + name: "PayType", + table: "PaymentConfig", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.UpdateData( + table: "PaymentConfig", + keyColumn: "Id", + keyValue: 1, + column: "PayType", + value: 1); + + migrationBuilder.UpdateData( + table: "PaymentConfig", + keyColumn: "Id", + keyValue: 2, + column: "PayType", + value: 1); + + migrationBuilder.UpdateData( + table: "PaymentConfig", + keyColumn: "Id", + keyValue: 3, + column: "PayType", + value: 1); + + migrationBuilder.UpdateData( + table: "PaymentConfig", + keyColumn: "Id", + keyValue: 4, + column: "PayType", + value: 1); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 31, 6, 10, 31, 712, DateTimeKind.Utc).AddTicks(1486)); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "PayType", + table: "PaymentConfig"); + + migrationBuilder.InsertData( + table: "PaymentConfig", + columns: new[] { "Id", "AppId", "Description", "ExtraSettingsJson", "GatewayUrl", "IsEnabled", "Method", "NotifyUrl", "PublicKey", "SecretKey" }, + values: new object[] { 5, "", null, null, "", false, 4, "", "", "" }); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 30, 14, 58, 7, 232, DateTimeKind.Utc).AddTicks(4921)); + } + } +} diff --git a/Apimanager_backend/Migrations/20250731074034_add_paymentconfig_url.Designer.cs b/Apimanager_backend/Migrations/20250731074034_add_paymentconfig_url.Designer.cs new file mode 100644 index 0000000..aaafd9a --- /dev/null +++ b/Apimanager_backend/Migrations/20250731074034_add_paymentconfig_url.Designer.cs @@ -0,0 +1,722 @@ +// +using System; +using Apimanager_backend.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20250731074034_add_paymentconfig_url")] + partial class add_paymentconfig_url + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Endpoint") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("IsThirdParty") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Endpoint") + .IsUnique(); + + b.HasIndex("PackageId"); + + b.ToTable("Apis"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("CallResult") + .HasColumnType("int"); + + b.Property("CallTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("UserId"); + + b.ToTable("CallLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("ApiPackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("ApiPackageId"); + + b.ToTable("ApiPackageItem"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("Request") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Response") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ResponseType") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.ToTable("ApiRequestExample"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CallLimit") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("OneMinuteLimit") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("decimal(65,30)"); + + b.HasKey("Id"); + + b.ToTable("Apipackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Log", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Exception") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LogLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MessageTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("Logs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("varchar(45)"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.Property("TargetType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("UserAgent") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("OperationLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("OrderNumber") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("OrderType") + .HasColumnType("int"); + + b.Property("PaiAt") + .HasColumnType("datetime(6)"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ThirdPartyOrderId") + .HasColumnType("varchar(255)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OrderNumber") + .IsUnique(); + + b.HasIndex("ThirdPartyOrderId") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.PaymentConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ExtraSettingsJson") + .HasColumnType("longtext"); + + b.Property("GatewayUrl") + .HasColumnType("longtext"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("NotifyUrl") + .HasColumnType("longtext"); + + b.Property("PayType") + .HasColumnType("int"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("SecretKey") + .HasColumnType("longtext"); + + b.Property("Url") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("paymentConfigs"); + + b.HasData( + new + { + Id = 1, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 0, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 2, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 1, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 3, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 3, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 4, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 2, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigBody") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ConfigName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SystemConfigs"); + + b.HasData( + new + { + Id = 1, + ConfigBody = "青蓝", + ConfigName = "SystemName" + }, + new + { + Id = 2, + ConfigBody = "描述", + ConfigName = "SystemDescription" + }, + new + { + Id = 3, + ConfigBody = "", + ConfigName = "LogoLocation" + }, + new + { + Id = 4, + ConfigBody = "", + ConfigName = "FaviconLocation" + }, + new + { + Id = 5, + ConfigBody = "13000000000", + ConfigName = "Phone" + }, + new + { + Id = 6, + ConfigBody = "admin@admin.com", + ConfigName = "Email" + }, + new + { + Id = 7, + ConfigBody = "{\"RegisterOn\":true,\"Emailvalidate\":true}", + ConfigName = "RegisterConfig" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .HasColumnType("longtext"); + + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsBan") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("PassHash") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasData( + new + { + Id = -1, + Balance = 0m, + CreatedAt = new DateTime(2025, 7, 31, 7, 40, 33, 590, DateTimeKind.Utc).AddTicks(5484), + Email = "admin1@admin.com", + IsBan = false, + IsDelete = false, + PassHash = "e10adc3949ba59abbe56e057f20f883e", + Username = "admin" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.Property("PurchasedAt") + .HasColumnType("datetime(6)"); + + b.Property("RemainingCalls") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Role") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Apis") + .HasForeignKey("PackageId"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiCalls") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("CallLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.Apipackage", "ApiPackage") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiPackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("ApiPackage"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiRequestExamples") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("operationLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Orders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Packages") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Packages") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Navigation("ApiCalls"); + + b.Navigation("ApiPackageItems"); + + b.Navigation("ApiRequestExamples"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Navigation("ApiPackageItems"); + + b.Navigation("Apis"); + + b.Navigation("Packages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Navigation("CallLogs"); + + b.Navigation("Orders"); + + b.Navigation("Packages"); + + b.Navigation("Roles"); + + b.Navigation("operationLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apimanager_backend/Migrations/20250731074034_add_paymentconfig_url.cs b/Apimanager_backend/Migrations/20250731074034_add_paymentconfig_url.cs new file mode 100644 index 0000000..b5315bd --- /dev/null +++ b/Apimanager_backend/Migrations/20250731074034_add_paymentconfig_url.cs @@ -0,0 +1,98 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + /// + public partial class add_paymentconfig_url : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_PaymentConfig", + table: "PaymentConfig"); + + migrationBuilder.RenameTable( + name: "PaymentConfig", + newName: "paymentConfigs"); + + migrationBuilder.AddColumn( + name: "Url", + table: "paymentConfigs", + type: "longtext", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AddPrimaryKey( + name: "PK_paymentConfigs", + table: "paymentConfigs", + column: "Id"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 31, 7, 40, 33, 590, DateTimeKind.Utc).AddTicks(5484)); + + migrationBuilder.UpdateData( + table: "paymentConfigs", + keyColumn: "Id", + keyValue: 1, + column: "Url", + value: null); + + migrationBuilder.UpdateData( + table: "paymentConfigs", + keyColumn: "Id", + keyValue: 2, + column: "Url", + value: null); + + migrationBuilder.UpdateData( + table: "paymentConfigs", + keyColumn: "Id", + keyValue: 3, + column: "Url", + value: null); + + migrationBuilder.UpdateData( + table: "paymentConfigs", + keyColumn: "Id", + keyValue: 4, + column: "Url", + value: null); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_paymentConfigs", + table: "paymentConfigs"); + + migrationBuilder.DropColumn( + name: "Url", + table: "paymentConfigs"); + + migrationBuilder.RenameTable( + name: "paymentConfigs", + newName: "PaymentConfig"); + + migrationBuilder.AddPrimaryKey( + name: "PK_PaymentConfig", + table: "PaymentConfig", + column: "Id"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 31, 6, 10, 31, 712, DateTimeKind.Utc).AddTicks(1486)); + } + } +} diff --git a/Apimanager_backend/Migrations/20250731104930_add_user_Avatar.Designer.cs b/Apimanager_backend/Migrations/20250731104930_add_user_Avatar.Designer.cs new file mode 100644 index 0000000..3ce77f7 --- /dev/null +++ b/Apimanager_backend/Migrations/20250731104930_add_user_Avatar.Designer.cs @@ -0,0 +1,725 @@ +// +using System; +using Apimanager_backend.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20250731104930_add_user_Avatar")] + partial class add_user_Avatar + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Endpoint") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("IsThirdParty") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Endpoint") + .IsUnique(); + + b.HasIndex("PackageId"); + + b.ToTable("Apis"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("CallResult") + .HasColumnType("int"); + + b.Property("CallTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("UserId"); + + b.ToTable("CallLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("ApiPackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("ApiPackageId"); + + b.ToTable("ApiPackageItem"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("Request") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Response") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ResponseType") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.ToTable("ApiRequestExample"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CallLimit") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("OneMinuteLimit") + .HasColumnType("int"); + + b.Property("Price") + .HasColumnType("decimal(65,30)"); + + b.HasKey("Id"); + + b.ToTable("Apipackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Log", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Exception") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LogLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MessageTemplate") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("Logs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("varchar(45)"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.Property("TargetType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("UserAgent") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("OperationLogs"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("OrderNumber") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("OrderType") + .HasColumnType("int"); + + b.Property("PaiAt") + .HasColumnType("datetime(6)"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ThirdPartyOrderId") + .HasColumnType("varchar(255)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("OrderNumber") + .IsUnique(); + + b.HasIndex("ThirdPartyOrderId") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.PaymentConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ExtraSettingsJson") + .HasColumnType("longtext"); + + b.Property("GatewayUrl") + .HasColumnType("longtext"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("NotifyUrl") + .HasColumnType("longtext"); + + b.Property("PayType") + .HasColumnType("int"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("SecretKey") + .HasColumnType("longtext"); + + b.Property("Url") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("paymentConfigs"); + + b.HasData( + new + { + Id = 1, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 0, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 2, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 1, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 3, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 3, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 4, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 2, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigBody") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ConfigName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("SystemConfigs"); + + b.HasData( + new + { + Id = 1, + ConfigBody = "青蓝", + ConfigName = "SystemName" + }, + new + { + Id = 2, + ConfigBody = "描述", + ConfigName = "SystemDescription" + }, + new + { + Id = 3, + ConfigBody = "", + ConfigName = "LogoLocation" + }, + new + { + Id = 4, + ConfigBody = "", + ConfigName = "FaviconLocation" + }, + new + { + Id = 5, + ConfigBody = "13000000000", + ConfigName = "Phone" + }, + new + { + Id = 6, + ConfigBody = "admin@admin.com", + ConfigName = "Email" + }, + new + { + Id = 7, + ConfigBody = "{\"RegisterOn\":true,\"Emailvalidate\":true}", + ConfigName = "RegisterConfig" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiKey") + .HasColumnType("longtext"); + + b.Property("Avatar") + .HasColumnType("longtext"); + + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("IsBan") + .HasColumnType("tinyint(1)"); + + b.Property("IsDelete") + .HasColumnType("tinyint(1)"); + + b.Property("PassHash") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + + b.HasData( + new + { + Id = -1, + Balance = 0m, + CreatedAt = new DateTime(2025, 7, 31, 10, 49, 29, 419, DateTimeKind.Utc).AddTicks(6892), + Email = "admin1@admin.com", + IsBan = false, + IsDelete = false, + PassHash = "e10adc3949ba59abbe56e057f20f883e", + Username = "admin" + }); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.Property("PurchasedAt") + .HasColumnType("datetime(6)"); + + b.Property("RemainingCalls") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PackageId"); + + b.HasIndex("UserId"); + + b.ToTable("UserPackages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Role") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Apis") + .HasForeignKey("PackageId"); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiCalls") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("CallLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.Apipackage", "ApiPackage") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiPackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("ApiPackage"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiRequestExamples") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("operationLogs") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Order", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Orders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => + { + b.HasOne("Apimanager_backend.Models.Apipackage", "Package") + .WithMany("Packages") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Packages") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.UserRole", b => + { + b.HasOne("Apimanager_backend.Models.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Api", b => + { + b.Navigation("ApiCalls"); + + b.Navigation("ApiPackageItems"); + + b.Navigation("ApiRequestExamples"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => + { + b.Navigation("ApiPackageItems"); + + b.Navigation("Apis"); + + b.Navigation("Packages"); + }); + + modelBuilder.Entity("Apimanager_backend.Models.User", b => + { + b.Navigation("CallLogs"); + + b.Navigation("Orders"); + + b.Navigation("Packages"); + + b.Navigation("Roles"); + + b.Navigation("operationLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apimanager_backend/Migrations/20250731104930_add_user_Avatar.cs b/Apimanager_backend/Migrations/20250731104930_add_user_Avatar.cs new file mode 100644 index 0000000..8880fe2 --- /dev/null +++ b/Apimanager_backend/Migrations/20250731104930_add_user_Avatar.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Apimanager_backend.Migrations +{ + /// + public partial class add_user_Avatar : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Avatar", + table: "Users", + type: "longtext", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + columns: new[] { "Avatar", "CreatedAt" }, + values: new object[] { null, new DateTime(2025, 7, 31, 10, 49, 29, 419, DateTimeKind.Utc).AddTicks(6892) }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Avatar", + table: "Users"); + + migrationBuilder.UpdateData( + table: "Users", + keyColumn: "Id", + keyValue: -1, + column: "CreatedAt", + value: new DateTime(2025, 7, 31, 7, 40, 33, 590, DateTimeKind.Utc).AddTicks(5484)); + } + } +} diff --git a/Apimanager_backend/Migrations/ApiContextModelSnapshot.cs b/Apimanager_backend/Migrations/ApiContextModelSnapshot.cs index 4cce6c9..6e7236d 100644 --- a/Apimanager_backend/Migrations/ApiContextModelSnapshot.cs +++ b/Apimanager_backend/Migrations/ApiContextModelSnapshot.cs @@ -34,7 +34,7 @@ namespace Apimanager_backend.Migrations b.Property("Endpoint") .IsRequired() - .HasColumnType("longtext"); + .HasColumnType("varchar(255)"); b.Property("IsActive") .HasColumnType("tinyint(1)"); @@ -58,6 +58,9 @@ namespace Apimanager_backend.Migrations b.HasKey("Id"); + b.HasIndex("Endpoint") + .IsUnique(); + b.HasIndex("PackageId"); b.ToTable("Apis"); @@ -90,6 +93,27 @@ namespace Apimanager_backend.Migrations b.ToTable("CallLogs"); }); + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ApiId") + .HasColumnType("int"); + + b.Property("ApiPackageId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ApiId"); + + b.HasIndex("ApiPackageId"); + + b.ToTable("ApiPackageItem"); + }); + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => { b.Property("Id") @@ -243,6 +267,9 @@ namespace Apimanager_backend.Migrations b.Property("Description") .HasColumnType("longtext"); + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + b.Property("OrderNumber") .IsRequired() .HasColumnType("varchar(255)"); @@ -250,13 +277,19 @@ namespace Apimanager_backend.Migrations b.Property("OrderType") .HasColumnType("int"); + b.Property("PaiAt") + .HasColumnType("datetime(6)"); + + b.Property("PaymentType") + .HasColumnType("int"); + b.Property("Status") .HasColumnType("int"); b.Property("ThirdPartyOrderId") .HasColumnType("varchar(255)"); - b.Property("UpdatedAt") + b.Property("UpdatedAt") .HasColumnType("datetime(6)"); b.Property("UserId") @@ -275,6 +308,100 @@ namespace Apimanager_backend.Migrations b.ToTable("Orders"); }); + modelBuilder.Entity("Apimanager_backend.Models.PaymentConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ExtraSettingsJson") + .HasColumnType("longtext"); + + b.Property("GatewayUrl") + .HasColumnType("longtext"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Method") + .HasColumnType("int"); + + b.Property("NotifyUrl") + .HasColumnType("longtext"); + + b.Property("PayType") + .HasColumnType("int"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("SecretKey") + .HasColumnType("longtext"); + + b.Property("Url") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("paymentConfigs"); + + b.HasData( + new + { + Id = 1, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 0, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 2, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 1, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 3, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 3, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }, + new + { + Id = 4, + AppId = "", + GatewayUrl = "", + IsEnabled = false, + Method = 2, + NotifyUrl = "", + PayType = 1, + PublicKey = "", + SecretKey = "" + }); + }); + modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b => { b.Property("Id") @@ -347,6 +474,9 @@ namespace Apimanager_backend.Migrations b.Property("ApiKey") .HasColumnType("longtext"); + b.Property("Avatar") + .HasColumnType("longtext"); + b.Property("Balance") .HasColumnType("decimal(65,30)"); @@ -387,7 +517,7 @@ namespace Apimanager_backend.Migrations { Id = -1, Balance = 0m, - CreatedAt = new DateTime(2024, 11, 10, 13, 48, 10, 873, DateTimeKind.Utc).AddTicks(7811), + CreatedAt = new DateTime(2025, 7, 31, 10, 49, 29, 419, DateTimeKind.Utc).AddTicks(6892), Email = "admin1@admin.com", IsBan = false, IsDelete = false, @@ -474,6 +604,25 @@ namespace Apimanager_backend.Migrations b.Navigation("User"); }); + modelBuilder.Entity("Apimanager_backend.Models.ApiPackageItem", b => + { + b.HasOne("Apimanager_backend.Models.Api", "Api") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Apimanager_backend.Models.Apipackage", "ApiPackage") + .WithMany("ApiPackageItems") + .HasForeignKey("ApiPackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Api"); + + b.Navigation("ApiPackage"); + }); + modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b => { b.HasOne("Apimanager_backend.Models.Api", "Api") @@ -541,11 +690,15 @@ namespace Apimanager_backend.Migrations { b.Navigation("ApiCalls"); + b.Navigation("ApiPackageItems"); + b.Navigation("ApiRequestExamples"); }); modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b => { + b.Navigation("ApiPackageItems"); + b.Navigation("Apis"); b.Navigation("Packages"); diff --git a/Apimanager_backend/Models/Api.cs b/Apimanager_backend/Models/Api.cs index be2752a..60c633b 100644 --- a/Apimanager_backend/Models/Api.cs +++ b/Apimanager_backend/Models/Api.cs @@ -58,6 +58,7 @@ namespace Apimanager_backend.Models //导航属性 public Apipackage? Package { get; set; } + public ICollection ApiPackageItems { get; set; } public ICollection ApiCalls { get; set; } public ICollection ApiRequestExamples { get; set; } } diff --git a/Apimanager_backend/Models/ApiPackageItem.cs b/Apimanager_backend/Models/ApiPackageItem.cs new file mode 100644 index 0000000..95665c1 --- /dev/null +++ b/Apimanager_backend/Models/ApiPackageItem.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Apimanager_backend.Models +{ + [Table("ApiPackageItem")] + public class ApiPackageItem + { + public int Id { get; set; } + + public int ApiPackageId { get; set; } + public Apipackage ApiPackage { get; set; } = null!; + + public int ApiId { get; set; } + public Api Api { get; set; } = null!; + } +} diff --git a/Apimanager_backend/Models/Apipackage.cs b/Apimanager_backend/Models/Apipackage.cs index 2bac923..eb15cd7 100644 --- a/Apimanager_backend/Models/Apipackage.cs +++ b/Apimanager_backend/Models/Apipackage.cs @@ -44,6 +44,8 @@ namespace Apimanager_backend.Models //导航属性 public ICollection Apis { get; set; } + public ICollection ApiPackageItems { get; set; } public ICollection Packages { get; set; } + } } diff --git a/Apimanager_backend/Models/Order.cs b/Apimanager_backend/Models/Order.cs index 804b846..b4fdbb5 100644 --- a/Apimanager_backend/Models/Order.cs +++ b/Apimanager_backend/Models/Order.cs @@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations; namespace Apimanager_backend.Models { + [Index(nameof(OrderNumber), IsUnique = true)] public class Order { /// @@ -30,6 +31,9 @@ namespace Apimanager_backend.Models /// 订单金额 /// public decimal Amount { get; set; } // decimal(10, 2) + + //支付方式 + public PaymentType PaymentType { get; set; } /// /// 订单类型 @@ -46,16 +50,24 @@ namespace Apimanager_backend.Models /// public DateTime CreatedAt { get; set; } = DateTime.UtcNow; // timestamp + //支付完成时间 + public DateTime? PaiAt { get; set; } + /// /// 更新时间,订单状态更新时间 /// - public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; // timestamp + public DateTime? UpdatedAt { get; set; } = DateTime.UtcNow; // timestamp /// /// 订单描述,可选的详细信息 /// public string? Description { get; set; } // varchar(255) + /// + /// 软删除 + /// + public bool IsDeleted { get; set; } = false; + //导航属性 public User? User { get; set; } } diff --git a/Apimanager_backend/Models/PayType.cs b/Apimanager_backend/Models/PayType.cs new file mode 100644 index 0000000..ea15aa6 --- /dev/null +++ b/Apimanager_backend/Models/PayType.cs @@ -0,0 +1,9 @@ +namespace Apimanager_backend.Models +{ + public enum PayType + { + None = 0, + Official = 1, + Epay = 2 + } +} diff --git a/Apimanager_backend/Models/PaymentConfig.cs b/Apimanager_backend/Models/PaymentConfig.cs new file mode 100644 index 0000000..43acf37 --- /dev/null +++ b/Apimanager_backend/Models/PaymentConfig.cs @@ -0,0 +1,43 @@ +using System.ComponentModel.DataAnnotations; + +namespace Apimanager_backend.Models +{ + public class PaymentConfig + { + public int Id { get; set; } + + /// 支付方式(如 Alipay、WeChat、Stripe...) + [Required] + public PaymentType Method { get; set; } // varchar(50) + + //接口类型:官方/易支付等 + public string? Url { get; set; } + + [Required] + public PayType PayType { get; set; } + + /// 商户号或 AppId + public string? AppId { get; set; } + + /// 商户密钥 / 私钥 + public string? SecretKey { get; set; } + + /// 公钥(如支付宝公钥) + public string? PublicKey { get; set; } + + /// 回调地址(notify_url) + public string? NotifyUrl { get; set; } + + /// 支付网关地址(gateway URL) + public string? GatewayUrl { get; set; } + + /// 是否启用此配置 + public bool IsEnabled { get; set; } = true; + + /// 额外配置项,JSON 格式可扩展 + public string? ExtraSettingsJson { get; set; } // 可包含 cert 路径、支付版本等 + + /// 备注 + public string? Description { get; set; } + } +} diff --git a/Apimanager_backend/Models/PaymentConfigDto.cs b/Apimanager_backend/Models/PaymentConfigDto.cs new file mode 100644 index 0000000..f23eff9 --- /dev/null +++ b/Apimanager_backend/Models/PaymentConfigDto.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; + +namespace Apimanager_backend.Models +{ + public class PaymentConfigDto + { + public int Id { get; set; } + + /// 支付方式(如 Alipay、WeChat、Stripe...) + public PaymentType Method { get; set; } // varchar(50) + + /// 备注 + public string? Description { get; set; } + } +} diff --git a/Apimanager_backend/Models/PaymentType.cs b/Apimanager_backend/Models/PaymentType.cs new file mode 100644 index 0000000..3b2c584 --- /dev/null +++ b/Apimanager_backend/Models/PaymentType.cs @@ -0,0 +1,10 @@ +namespace Apimanager_backend.Models +{ + public enum PaymentType + { + AliPay = 0, + WxPay = 1, + Bank = 2, + QQPay =3 + } +} diff --git a/Apimanager_backend/Models/User.cs b/Apimanager_backend/Models/User.cs index 5e71322..0e7ece9 100644 --- a/Apimanager_backend/Models/User.cs +++ b/Apimanager_backend/Models/User.cs @@ -14,6 +14,7 @@ namespace Apimanager_backend.Models /// [Required] public string Username { get; set; } // varchar(20) + public string? Avatar { get; set; } /// /// 邮箱,唯一 diff --git a/Apimanager_backend/Models/UserRole.cs b/Apimanager_backend/Models/UserRole.cs index 1df0b7a..60b26a4 100644 --- a/Apimanager_backend/Models/UserRole.cs +++ b/Apimanager_backend/Models/UserRole.cs @@ -10,6 +10,6 @@ namespace Apimanager_backend.Models //导航属性 [JsonIgnore] - public User User { get; set; } + public User? User { get; set; } } } diff --git a/Apimanager_backend/Program.cs b/Apimanager_backend/Program.cs index 0b41235..ec6bbb0 100644 --- a/Apimanager_backend/Program.cs +++ b/Apimanager_backend/Program.cs @@ -1,7 +1,9 @@ -using Apimanager_backend.Config; +using Apimanager_backend.Config; using Apimanager_backend.Data; +using Apimanager_backend.Dtos; using Apimanager_backend.Filters; using Apimanager_backend.Filters.ExceptionFilter; +using Apimanager_backend.Services; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Serilog; @@ -17,7 +19,7 @@ IConfiguration configuration = new ConfigurationBuilder() .Build(); string? redStr = configuration["Redis:ConnectionString"]; string? constr = configuration.GetConnectionString("DefaultConnection"); -//־ +//日志服务 /* Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() @@ -35,9 +37,9 @@ option.UseMySql(constr, MySqlServerVersion.AutoDetect(constr)) builder.Services.AddAllService(configuration); builder.Services.AddControllers(options => { - //ģ֤ + //模型验证 options.Filters.Add(); - //Exception + //Exception过滤器 options.Filters.Add(); }).ConfigureApiBehaviorOptions(option => { @@ -53,6 +55,80 @@ builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); +app.Use(async (ctx, next) => +{ + var controller = ctx.Request.RouteValues["controller"]?.ToString(); // YourController + var action = ctx.Request.RouteValues["action"]?.ToString(); + if (controller != "Public" || action != "Invoke") + { + await next(); + return; + } + if (ctx.Request.Headers.TryGetValue("Authorization", out var hdr) && + hdr.ToString().StartsWith("Bearer ")) + { + var token = hdr.ToString().Substring("Bearer ".Length).Trim(); + var code = ctx.Request.RouteValues["code"]!.ToString()!; + RateLimiterDto rateLimiterDto = new RateLimiterDto(); + var userService = ctx.RequestServices.GetRequiredService(); + var apiService = ctx.RequestServices.GetRequiredService(); + var apiPackageItemService = ctx.RequestServices.GetRequiredService(); + var userPackageService = ctx.RequestServices.GetRequiredService(); + var user = await userService.GetByTokenAsync(token); + var api = await apiService.GetApiInfoByEndpointAsync(code); + var apiPackages = await apiPackageItemService.GetApiPackageItemsByApiIdAsync(api.Id); + + if (user == null || apiPackages.Count == 0) + { + ctx.Items["rateLimit"] = null; + } + else + { + var userPackages = await userPackageService.GetUserPackagesByUserIdAsync(user.Id); + if (userPackages.Count == 0) + { + ctx.Items["rateLimit"] = null; + } + // 提取 list2 中的所有 package.id,变成 HashSet 提高查找效率 + var apipackage1 = new HashSet(apiPackages.Select(x => x.ApiPackage.Id)); + + + var uPackages = userPackages + .Where(x => apipackage1.Contains(x.Package.Id)).ToList(); + // 从 list1 中筛选出 user.id 存在于 list2 的项 + var commonPackages = uPackages + .Select(x => x.Package) + .ToList(); + var package = commonPackages.Count > 0 ? commonPackages.MaxBy(x => x.OneMinuteLimit) : null; + var data = package == null ? null : new RateLimiterDto() + { + UserId = user.Id, + RateLimit = package.OneMinuteLimit + }; + ctx.Items["rateLimit"] = data; + ctx.Items["userPackages"] = uPackages; + } + } + else + { + ctx.Items["rateLimit"] = null; + } + if (ctx.Items["rateLimit"] == null) + { + ctx.Response.StatusCode = 429; + ctx.Response.ContentType = "application/json"; + await ctx.Response.WriteAsJsonAsync(new ResponseBase() + { + Code = 3003, + Data = null, + Message = "未授权或访问频率受限" + }); + return; // ⛔ 不调用 next(),请求终止 + } + await next(); + return; +}); + // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { @@ -66,6 +142,22 @@ app.UseCors("AllowAll"); app.UseAuthentication(); app.UseAuthorization(); +app.UseRateLimiter(); +/* +app.Use(async (context, next) => +{ + var controller = context.Request.RouteValues["controller"]?.ToString(); // YourController + var action = context.Request.RouteValues["action"]?.ToString(); // Invoke + var code = context.Request.RouteValues["code"]?.ToString(); // ← 就是你要的 GetUserList + + Console.WriteLine($"控制器: {controller}, 实际方法: {code}(映射到 Invoke)"); + + // 你可以根据 code 设置速率限制策略、权限校验等 + + await next(); +}); +*/ + app.MapControllers(); app.Run(); diff --git a/Apimanager_backend/Services/ApiPackageItemService.cs b/Apimanager_backend/Services/ApiPackageItemService.cs new file mode 100644 index 0000000..e4dd59b --- /dev/null +++ b/Apimanager_backend/Services/ApiPackageItemService.cs @@ -0,0 +1,22 @@ +using Apimanager_backend.Data; +using Apimanager_backend.Models; +using Microsoft.EntityFrameworkCore; + +namespace Apimanager_backend.Services +{ + public class ApiPackageItemService : IApiPackageItemService + { + private ApiContext _context; + private ILogger _logger; + public ApiPackageItemService(ApiContext context,ILogger logger) + { + _context = context; + _logger = logger; + } + public async Task> GetApiPackageItemsByApiIdAsync(int ApiId) + { + IQueryable query = _context.apiPackageItems.Include(x => x.ApiPackage).Where(x => x.ApiId == ApiId); + return await query.ToListAsync(); + } + } +} diff --git a/Apimanager_backend/Services/ApiService.cs b/Apimanager_backend/Services/ApiService.cs index d8604e7..6f542f8 100644 --- a/Apimanager_backend/Services/ApiService.cs +++ b/Apimanager_backend/Services/ApiService.cs @@ -116,5 +116,16 @@ namespace Apimanager_backend.Services return await context.Apis.CountAsync(); } #endregion + #region 通过Api路径获取api信息 + public async Task GetApiInfoByEndpointAsync(string endpoint) + { + var apiInfo = await context.Apis.FirstOrDefaultAsync(x => x.Endpoint == endpoint); + if (apiInfo == null) + { + throw new BaseException(3002, "API不存在"); + } + return mapper.Map(apiInfo); + } + #endregion } } diff --git a/Apimanager_backend/Services/IApiPackageItemService.cs b/Apimanager_backend/Services/IApiPackageItemService.cs new file mode 100644 index 0000000..e33452f --- /dev/null +++ b/Apimanager_backend/Services/IApiPackageItemService.cs @@ -0,0 +1,10 @@ + +using Apimanager_backend.Models; + +namespace Apimanager_backend.Services +{ + public interface IApiPackageItemService + { + Task> GetApiPackageItemsByApiIdAsync(int ApiId); + } +} diff --git a/Apimanager_backend/Services/IApiService.cs b/Apimanager_backend/Services/IApiService.cs index 0f91d72..d9b8810 100644 --- a/Apimanager_backend/Services/IApiService.cs +++ b/Apimanager_backend/Services/IApiService.cs @@ -55,6 +55,12 @@ namespace Apimanager_backend.Services /// /// public Task ApiCountAsync(); + /// + /// 通过api路径获取api信息 + /// + /// api路径 + /// + public Task GetApiInfoByEndpointAsync(string endpoint); } } diff --git a/Apimanager_backend/Services/IOrderService.cs b/Apimanager_backend/Services/IOrderService.cs new file mode 100644 index 0000000..0109b4a --- /dev/null +++ b/Apimanager_backend/Services/IOrderService.cs @@ -0,0 +1,24 @@ +using Apimanager_backend.Dtos; +using Apimanager_backend.Models; + +namespace Apimanager_backend.Services +{ + public interface IOrderService + { + /// + /// 获取订单列表 + /// + /// 页索引 + /// 页大小 + /// 是否倒序 + /// + Task> GetOrdersAsync(int pageIndex, int pageSize,bool desc,int? userId); + /// + /// 创建订单 + /// + /// 订单信息 + /// + Task CreateOrderAsync(OrderDto order); + Task UpdateOrderAsync(OrderDto order); + } +} diff --git a/Apimanager_backend/Services/IPayService.cs b/Apimanager_backend/Services/IPayService.cs new file mode 100644 index 0000000..fc2af3b --- /dev/null +++ b/Apimanager_backend/Services/IPayService.cs @@ -0,0 +1,10 @@ +using Apimanager_backend.Dtos; +using Apimanager_backend.Models; + +namespace Apimanager_backend.Services +{ + public interface IPayService + { + Task CreateEpay(Order order,PaymentConfig paymentConfig,string returnUrl); + } +} diff --git a/Apimanager_backend/Services/IPaymentConfigService.cs b/Apimanager_backend/Services/IPaymentConfigService.cs new file mode 100644 index 0000000..bff6136 --- /dev/null +++ b/Apimanager_backend/Services/IPaymentConfigService.cs @@ -0,0 +1,10 @@ +using Apimanager_backend.Models; + +namespace Apimanager_backend.Services +{ + public interface IPaymentConfigService + { + Task GetPaymentConfigInfoByTypeAsync(string payType); + Task> GetAllPaymentAsync(); + } +} diff --git a/Apimanager_backend/Services/IUserPackageService.cs b/Apimanager_backend/Services/IUserPackageService.cs new file mode 100644 index 0000000..b7fc6bb --- /dev/null +++ b/Apimanager_backend/Services/IUserPackageService.cs @@ -0,0 +1,9 @@ +using Apimanager_backend.Models; + +namespace Apimanager_backend.Services +{ + public interface IUserPackageService + { + Task> GetUserPackagesByUserIdAsync(int userId); + } +} diff --git a/Apimanager_backend/Services/IUserService.cs b/Apimanager_backend/Services/IUserService.cs index 7da04dc..93b0366 100644 --- a/Apimanager_backend/Services/IUserService.cs +++ b/Apimanager_backend/Services/IUserService.cs @@ -47,5 +47,18 @@ namespace Apimanager_backend.Services /// 邮箱 /// Task IsEmailExist(string email); + + /// + /// 通过ApiToken获取用户 + /// + /// + /// + Task GetByTokenAsync(string token); + /// + /// 更新用户头像 + /// + /// + /// + Task UpdateUserAvatarAsync(int userId,string url); } } diff --git a/Apimanager_backend/Services/OrderService.cs b/Apimanager_backend/Services/OrderService.cs new file mode 100644 index 0000000..8014376 --- /dev/null +++ b/Apimanager_backend/Services/OrderService.cs @@ -0,0 +1,104 @@ +using Apimanager_backend.Data; +using Apimanager_backend.Dtos; +using Apimanager_backend.Exceptions; +using Apimanager_backend.Models; +using Apimanager_backend.Tools; +using AutoMapper; +using Microsoft.EntityFrameworkCore; + +namespace Apimanager_backend.Services +{ + public class OrderService:IOrderService + { + private ApiContext _apiContext; + private IMapper mapper; + private ILogger logger; + public OrderService(ApiContext apiContext,IMapper mapper,ILogger logger) + { + _apiContext = apiContext; + this.mapper = mapper; + this.logger = logger; + } + #region 创建订单 + /// + /// 创建订单 + /// + /// 订单信息 + /// + /// + public async Task CreateOrderAsync(OrderDto order) + { + var transaction = await _apiContext.Database.BeginTransactionAsync(); + try + { + Order orderInfo = mapper.Map(order); + //初始化信息 + orderInfo.Status = OrderStatus.Pending; + orderInfo.CreatedAt = DateTime.Now; + orderInfo.OrderNumber = OrderNumberGenerator.Generate(order.UserId); + _apiContext.Orders.Add(orderInfo); + await _apiContext.SaveChangesAsync(); + await transaction.CommitAsync(); + return orderInfo; + }catch(Exception e) + { + //异常回滚 + await transaction.RollbackAsync(); + logger.LogError(e.Message); + throw new BaseException(4006,"支付系统错误"); + } + } + #endregion + #region 获取订单列表 + /// + /// 获取订单列表 + /// + /// 索引 + /// 页大小 + /// 是否倒序 + /// 指定用户订单 + /// + public async Task> GetOrdersAsync(int pageIndex, int pageSize, bool desc, int? userId) + { + IQueryable query = _apiContext.Orders.AsQueryable().OrderBy(x => x.Id); + if(userId != null) + { + query.Where(x => x.UserId == userId); + } + //倒序 + if (desc) + { + query.OrderDescending(); + } + //分页 + query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize); + return await query.ToListAsync(); + } + #endregion + + #region 更新订单状态 + public async Task UpdateOrderAsync(OrderDto order) + { + try + { + var data = await _apiContext.Orders.SingleOrDefaultAsync(x => x.OrderNumber == order.OrderNumber || x.ThirdPartyOrderId == order.ThirdPartyOrderId); + if (data == null) + { + throw new BaseException(4003, "订单未找到"); + } + data.UpdatedAt = DateTime.Now; + data.Status = order.Status; + data.PaiAt = order.Status == OrderStatus.Completed ? DateTime.Now : null; + _apiContext.Orders.Update(data); + await _apiContext.SaveChangesAsync(); + return true; + }catch(Exception e) + { + logger.LogError(e.Message); + throw new BaseException(4003, "订单未找到"); + } + } + #endregion + + } +} diff --git a/Apimanager_backend/Services/PayService.cs b/Apimanager_backend/Services/PayService.cs new file mode 100644 index 0000000..e6ce878 --- /dev/null +++ b/Apimanager_backend/Services/PayService.cs @@ -0,0 +1,48 @@ +using Apimanager_backend.Data; +using Apimanager_backend.Dtos; +using Apimanager_backend.Exceptions; +using Apimanager_backend.Models; +using Apimanager_backend.Tools; +using AutoMapper; +using Microsoft.EntityFrameworkCore; + +namespace Apimanager_backend.Services +{ + public class PayService : IPayService + { + private IMapper _mapper; + private ILogger _logger; + private ApiContext _context; + public PayService(IMapper mapper,ILogger logger,ApiContext apiContext) + { + _mapper = mapper; + _logger = logger; + _context = apiContext; + } + public async Task CreateEpay(Order order, PaymentConfig paymentConfig,string returnUrl) + { + try + { + var param = new Dictionary(); + param["pid"] = paymentConfig.AppId; + param["type"] = order.PaymentType.ToString().ToLower(); + param["out_trade_no"] = order.OrderNumber; + param["notify_url"] = paymentConfig.NotifyUrl ?? ""; + param["return_url"] = returnUrl; + param["name"] = "余额充值"; + param["money"] = order.Amount.ToString(); + param["clientip"] = "192.168.5.1"; + param["device"] = "pc"; + var res = await EpayHelper.ApiPayAsync(param, paymentConfig.SecretKey, paymentConfig.Url); + order.ThirdPartyOrderId = res.trade_no; + _context.Orders.Update(order); + await _context.SaveChangesAsync(); + return _mapper.Map(res); + }catch(Exception e) + { + _logger.LogError(e.Message); + throw new BaseException(4001,"支付请求无效"); + } + } + } +} diff --git a/Apimanager_backend/Services/PaymentConfigService.cs b/Apimanager_backend/Services/PaymentConfigService.cs new file mode 100644 index 0000000..969bf0b --- /dev/null +++ b/Apimanager_backend/Services/PaymentConfigService.cs @@ -0,0 +1,40 @@ +using Apimanager_backend.Data; +using Apimanager_backend.Exceptions; +using Apimanager_backend.Models; +using AutoMapper; +using Microsoft.EntityFrameworkCore; + +namespace Apimanager_backend.Services +{ + public class PaymentConfigService : IPaymentConfigService + { + private ApiContext _context; + private ILogger _logger; + private IMapper _mapper; + public PaymentConfigService(ApiContext context,ILogger logger,IMapper mapper) + { + _context = context; + _logger = logger; + _mapper = mapper; + } + public async Task> GetAllPaymentAsync() + { + var data = await _context.paymentConfigs.Where(x => x.IsEnabled).ToListAsync(); + return _mapper.Map>(data); + } + + public async Task GetPaymentConfigInfoByTypeAsync(string payType) + { + if(!Enum.TryParse(payType, true, out PaymentType parsedPayType)) + { + throw new BaseException(4001, "未配置该支付方式的通道"); + } + var data = await _context.paymentConfigs.SingleOrDefaultAsync(x => x.Method == parsedPayType); + if(data == null) + { + throw new BaseException(4001, "未配置该支付方式的通道"); + } + return data; + } + } +} diff --git a/Apimanager_backend/Services/PluginLoaderService.cs b/Apimanager_backend/Services/PluginLoaderService.cs new file mode 100644 index 0000000..f04fdea --- /dev/null +++ b/Apimanager_backend/Services/PluginLoaderService.cs @@ -0,0 +1,62 @@ +using Apimanager_backend.Data; +using Public; +using System.Reflection; + +namespace Apimanager_backend.Services +{ + // PluginLoaderService.cs + public class PluginLoaderService + { + private readonly IWebHostEnvironment _env; + private readonly ILogger _logger; + + public PluginLoaderService( + IWebHostEnvironment env, + ILogger logger) + { + _env = env; + _logger = logger; + } + + public void LoadPlugins(IServiceCollection services) + { + var pluginsDir = Path.Combine(_env.ContentRootPath, "ApiHandler"); + Directory.CreateDirectory(pluginsDir); + + foreach (var dllPath in Directory.GetFiles(pluginsDir, "*.dll")) + { + try + { + var assembly = LoadPluginAssembly(dllPath); + RegisterPluginServices(assembly, services); + _logger.LogInformation($"已加载插件: {Path.GetFileName(dllPath)}"); + } + catch (Exception ex) + { + _logger.LogError(ex, $"加载插件失败: {dllPath}"); + } + } + } + + private Assembly LoadPluginAssembly(string dllPath) + { + // 使用隔离的加载上下文 + var loadContext = new PluginLoadContext(dllPath); + return loadContext.LoadFromAssemblyPath(dllPath); + } + + private void RegisterPluginServices(Assembly assembly, IServiceCollection services) + { + foreach (var type in assembly.GetTypes()) + { + if (typeof(IBillableApiHandler).IsAssignableFrom(type) && + !type.IsInterface && + !type.IsAbstract) + { + services.AddTransient(typeof(IBillableApiHandler), type); + services.AddTransient(type); // 同时注册具体类型 + } + } + } + } +} diff --git a/Apimanager_backend/Services/UserPackageService.cs b/Apimanager_backend/Services/UserPackageService.cs new file mode 100644 index 0000000..ba76d71 --- /dev/null +++ b/Apimanager_backend/Services/UserPackageService.cs @@ -0,0 +1,21 @@ + +using Apimanager_backend.Data; +using Apimanager_backend.Models; +using Microsoft.EntityFrameworkCore; + +namespace Apimanager_backend.Services +{ + public class UserPackageService : IUserPackageService + { + private ApiContext _context; + public UserPackageService(ApiContext apiContext) + { + _context = apiContext; + } + public async Task> GetUserPackagesByUserIdAsync(int userId) + { + IQueryable query = _context.UserPackages.Include(x => x.Package).Where(x => x.UserId == userId); + return await query.ToListAsync(); + } + } +} diff --git a/Apimanager_backend/Services/UserService.cs b/Apimanager_backend/Services/UserService.cs index 95a583f..cbf843f 100644 --- a/Apimanager_backend/Services/UserService.cs +++ b/Apimanager_backend/Services/UserService.cs @@ -101,5 +101,29 @@ namespace Apimanager_backend.Services await apiContext.SaveChangesAsync(); return mapper.Map(user); } + + public async Task GetByTokenAsync(string token) + { + User? user = await apiContext.Users.Include(x => x.Roles).Include(x => x.Packages).SingleOrDefaultAsync(x => x.ApiKey == token); + //未找到用户 + if (user == null) + { + return null; + } + return mapper.Map(user); + } + + public async Task UpdateUserAvatarAsync(int userId,string url) + { + var user = await apiContext.Users.FirstOrDefaultAsync(x => x.Id == userId); + if (user == null) + { + return false; + } + user.Avatar = url; + apiContext.Users.Update(user); + await apiContext.SaveChangesAsync(); + return true; + } } } diff --git a/Apimanager_backend/Tools/BillableApiDispatcher.cs b/Apimanager_backend/Tools/BillableApiDispatcher.cs new file mode 100644 index 0000000..77280d3 --- /dev/null +++ b/Apimanager_backend/Tools/BillableApiDispatcher.cs @@ -0,0 +1,100 @@ +using Apimanager_backend.Models; +using System.Reflection; +using System; +using Apimanager_backend.Data; +using Microsoft.EntityFrameworkCore; +using Apimanager_backend.Exceptions; +using Apimanager_backend.Dtos; +using Public; +using Apimanager_backend.Services; + +namespace Apimanager_backend.Tools +{ + public class BillableApiDispatcher + { + private readonly IServiceProvider _serviceProvider; + private readonly ApiContext _db; + private PluginLoaderService _pluginLoaderService; + + public BillableApiDispatcher(IServiceProvider sp, ApiContext db,PluginLoaderService pluginLoaderService) + { + _serviceProvider = sp; + _db = db; + _pluginLoaderService = pluginLoaderService; + } + + public async Task DispatchAsync(string webPath,int apiId,string code, ApiCallContext context) + { + //_pluginLoaderService.LoadPlugins(new ServiceCollection()); + // 1. 安全验证 + string dllPath = webPath + "\\ApiHandler\\" + code + ".dll"; + if (!System.IO.File.Exists(dllPath)) + throw new BaseException(3002, "接口实现未找到"); + + // 2. 加载程序集 + var assembly = Assembly.LoadFrom(dllPath); // 或使用 AssemblyLoadContext.Default.LoadFromAssemblyPath + + // 3. 查找实现类 + var type = assembly.GetTypes() + .FirstOrDefault(t => + typeof(IBillableApiHandler).IsAssignableFrom(t) && + !t.IsInterface && + !t.IsAbstract && + t.Name.Equals(code, StringComparison.OrdinalIgnoreCase)); + if (type == null) + throw new BaseException(3002,"接口实现未找到"); + + List userPackages = context.HttpContext.Items["userPackages"] as List; + List userPackageList = null; + + if (userPackages == null || !(userPackages is IEnumerable)) + { + throw new BaseException(3004, "未购买该API套餐或权限不足"); + } + + userPackageList = ((IEnumerable)userPackages).ToList(); + + userPackageList = userPackageList.Where(x => x.ExpiryDate > DateTime.Now).ToList(); + + if (userPackageList.Count == 0) + { + throw new BaseException(3004, "未购买该API套餐或权限不足"); + } + + + var maxCountUserPackage = userPackageList.MaxBy(x => x.RemainingCalls); + + if (maxCountUserPackage.RemainingCalls <= 0) + { + throw new BaseException(3004, "套餐可用额度不足"); + } + + var uPackage = await _db.UserPackages.SingleOrDefaultAsync(x => x.Id == maxCountUserPackage.Id); + if (uPackage == null) + { + throw new BaseException(3004, "未购买该API套餐或权限不足"); + } + + uPackage.RemainingCalls -= 1; + + _db.UserPackages.Update(uPackage); + + var handler = (IBillableApiHandler)Activator.CreateInstance(type)!; + + // 执行接口 + var result = await handler.ExecuteAsync(context); + + // 记录调用日志 + _db.CallLogs.Add(new ApiCallLog + { + ApiId = apiId, + UserId = context.UserId, + CallTime = DateTime.UtcNow + }); + + await _db.SaveChangesAsync(); + return result; + } + + } +} diff --git a/Apimanager_backend/Tools/EpayHelper.cs b/Apimanager_backend/Tools/EpayHelper.cs new file mode 100644 index 0000000..1fd3f6d --- /dev/null +++ b/Apimanager_backend/Tools/EpayHelper.cs @@ -0,0 +1,53 @@ +using Apimanager_backend.Dtos; +using Newtonsoft.Json; +using System.Security.Cryptography; +using System.Text; + +namespace Apimanager_backend.Tools +{ + public static class EpayHelper + { + /// + /// 创建签名 + /// + public static string CreateSign(Dictionary parameters, string key) + { + var sorted = parameters + .Where(kv => !string.IsNullOrEmpty(kv.Value) && kv.Key != "sign" && kv.Key != "sign_type") + .OrderBy(kv => kv.Key) + .ToList(); + + string query = string.Join("&", sorted.Select(kv => $"{kv.Key}={kv.Value}")); + string toSign = query + key; + + using (var md5 = MD5.Create()) + { + byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(toSign)); + return BitConverter.ToString(hash).Replace("-", "").ToLower(); + } + } + /// + /// 发起API支付(返回 json) + /// + public static async Task ApiPayAsync(Dictionary parameters, string key,string baseUrl) + { + parameters["sign_type"] = "MD5"; + parameters["sign"] = CreateSign(parameters, key); + + using var client = new HttpClient(); + var content = new FormUrlEncodedContent(parameters); + var response = await client.PostAsync($"{baseUrl}/mapi.php", content); + return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + } + + /// + /// 校验签名(通常用于异步通知/页面跳转) + /// + public static bool VerifySign(Dictionary parameters, string key) + { + if (!parameters.TryGetValue("sign", out string originalSign)) return false; + string newSign = CreateSign(parameters, key); + return originalSign.Equals(newSign, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/Apimanager_backend/Tools/OrderNumberGenerator.cs b/Apimanager_backend/Tools/OrderNumberGenerator.cs new file mode 100644 index 0000000..fa7ae36 --- /dev/null +++ b/Apimanager_backend/Tools/OrderNumberGenerator.cs @@ -0,0 +1,14 @@ +namespace Apimanager_backend.Tools +{ + public static class OrderNumberGenerator + { + public static string Generate(int userId = 0, string prefix = "ORD") + { + var datePart = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); // 17位 + var userPart = (userId % 10000).ToString("D4"); // 后4位用户ID + var randPart = Random.Shared.Next(1000, 9999).ToString(); // 4位随机数 + + return $"{prefix}{datePart}{userPart}{randPart}"; // 最终:ORD + 时间 + 用户 + 随机数 + } + } +} diff --git a/Apimanager_backend/Tools/UserInfoHelper.cs b/Apimanager_backend/Tools/UserInfoHelper.cs new file mode 100644 index 0000000..d7c98c1 --- /dev/null +++ b/Apimanager_backend/Tools/UserInfoHelper.cs @@ -0,0 +1,29 @@ +namespace Apimanager_backend.Tools +{ + public static class UserInfoHelper + { + public static string GetClientIp(HttpContext context) + { + var ip = context.Connection.RemoteIpAddress?.ToString(); + + // 支持代理(如 Nginx)时使用 X-Forwarded-For + if (context.Request.Headers.ContainsKey("X-Forwarded-For")) + { + ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + } + + return ip ?? "unknown"; + } + public static string GetDeviceType(HttpContext context) + { + var userAgent = context.Request.Headers["User-Agent"].ToString().ToLower(); + + if (userAgent.Contains("mobile") || userAgent.Contains("android") || userAgent.Contains("iphone")) + return "mobile"; + + return "pc"; + } + + + } +} diff --git a/Apimanager_backend/uploads/avatars/-1_20250731191020.png b/Apimanager_backend/uploads/avatars/-1_20250731191020.png new file mode 100644 index 0000000..44611d0 Binary files /dev/null and b/Apimanager_backend/uploads/avatars/-1_20250731191020.png differ diff --git a/Apimanager_backend/uploads/avatars/-1_20250731191110.jpg b/Apimanager_backend/uploads/avatars/-1_20250731191110.jpg new file mode 100644 index 0000000..696bfe5 Binary files /dev/null and b/Apimanager_backend/uploads/avatars/-1_20250731191110.jpg differ diff --git a/Public/ApiCallContext.cs b/Public/ApiCallContext.cs new file mode 100644 index 0000000..e4e7fc0 --- /dev/null +++ b/Public/ApiCallContext.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Http; + +namespace Public +{ + public class ApiCallContext + { + public int UserId { get; set; } + public Dictionary Parameters { get; set; } = new(); + public HttpContext HttpContext { get; set; } = null!; + } + +} diff --git a/Public/IBillableApiHandler.cs b/Public/IBillableApiHandler.cs new file mode 100644 index 0000000..ccc505a --- /dev/null +++ b/Public/IBillableApiHandler.cs @@ -0,0 +1,8 @@ +namespace Public +{ + public interface IBillableApiHandler + { + /// 执行 API 主逻辑 + Task ExecuteAsync(ApiCallContext context); + } +} diff --git a/Public/Public.csproj b/Public/Public.csproj new file mode 100644 index 0000000..1730be6 --- /dev/null +++ b/Public/Public.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + +