修改配置文件

This commit is contained in:
南浔 2024-11-09 23:36:52 +08:00
commit 85b388624e
23 changed files with 1368 additions and 11 deletions

View File

@ -13,6 +13,8 @@ namespace Apimanager_backend.Config
.ForMember(dest => dest.PassHash, opt => opt.MapFrom(src => src.Password)); .ForMember(dest => dest.PassHash, opt => opt.MapFrom(src => src.Password));
CreateMap<Api, ApiInfoDto>(); CreateMap<Api, ApiInfoDto>();
CreateMap<CreateApiInfo, Api>(); CreateMap<CreateApiInfo, Api>();
CreateMap<Apipackage, PackageInfoDto>();
CreateMap<AddPackageDto, Apipackage>();
} }
} }
} }

View File

@ -14,10 +14,15 @@ namespace Apimanager_backend.Config
{ {
public static IServiceCollection AddAllService(this IServiceCollection services,IConfiguration configuration) public static IServiceCollection AddAllService(this IServiceCollection services,IConfiguration configuration)
{ {
services.AddCorsService(configuration);
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddJWTService(configuration); services.AddJWTService(configuration);
services.AddScoped<IUserService, UserService>(); services.AddScoped<IUserService, UserService>();
services.AddScoped<IAuthService, AuthService>(); services.AddScoped<IAuthService, AuthService>();
services.AddScoped<IAdminService, AdminService>();
services.AddScoped<IApiService, ApiService>();
services.AddScoped<IPackageService, PackageService>();
services.AddScoped<ISystemConfigService, SystemConfigService>();
services.AddSingleton<ITokenService, TokenService>(); services.AddSingleton<ITokenService, TokenService>();
services.AddSingleton<IRefreshTokenService, RefreshTokenService>(); services.AddSingleton<IRefreshTokenService, RefreshTokenService>();
services.AddSingleton<IEmailService, EmailService>(); services.AddSingleton<IEmailService, EmailService>();
@ -82,5 +87,18 @@ namespace Apimanager_backend.Config
context.Response.StatusCode = StatusCodes.Status401Unauthorized; context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync(JsonConvert.SerializeObject(res)); await context.Response.WriteAsync(JsonConvert.SerializeObject(res));
} }
public static IServiceCollection AddCorsService(this IServiceCollection services,IConfiguration configuration1)
{
services.AddCors(option =>
{
option.AddPolicy("AllowAll",builder =>
{
builder.AllowAnyHeader();
builder.AllowAnyMethod();
builder.AllowAnyOrigin();
});
});
return services;
}
} }
} }

View File

@ -0,0 +1,173 @@
using Apimanager_backend.Dtos;
using Apimanager_backend.Exceptions;
using Apimanager_backend.Models;
using Apimanager_backend.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Apimanager_backend.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class PackageController : ControllerBase
{
private readonly IPackageService packageService;
private readonly ILogger<PackageController> logger;
public PackageController(IPackageService packageService,ILogger<PackageController> logger)
{
this.packageService = packageService;
this.logger = logger;
}
#region
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<ActionResult<ResponseBase<PackageInfoDto>>> AddPackage(AddPackageDto addPackageDto)
{
var packageInfo = await packageService.AddPackageAsync(addPackageDto);
var res = new ResponseBase<PackageInfoDto>(packageInfo);
return Ok(res);
}
#endregion
#region
[HttpDelete]
[Authorize(Roles = "Admin")]
public async Task<ActionResult<ResponseBase<object?>>> DeletePackage(int packageId)
{
try
{
await packageService.DeletePackageAsync(packageId);
var res = new ResponseBase<object?>(null);
return Ok(res);
}catch(BaseException e)
{
var res = new ResponseBase<object?>(
code:e.code,
message:e.message,
data:null
);
return NotFound(res);
}
}
#endregion
#region
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<ActionResult<ResponseBase<PackageInfoDto?>>> UpdatePackage(int packageId, UpdatePackageDto updatePackageDto)
{
try
{
var packageInfo = await packageService.UpdatePackageAsync(packageId, updatePackageDto);
var res = new ResponseBase<PackageInfoDto?>(packageInfo);
return Ok(res);
}
catch (BaseException e)
{
var res = new ResponseBase<PackageInfoDto?>(
code:e.code,
message:e.message,
data:null
);
return NotFound(res);
}
}
#endregion
#region
[HttpGet]
[Authorize(Roles = "User")]
public async Task<ActionResult<ResponseBase<PackageInfoDto?>>> GetPackageInfo(int packageId)
{
try
{
var packageInfo = await packageService.PackageInfoByIdAsync(packageId);
var res = new ResponseBase<PackageInfoDto?>(packageInfo);
return Ok(res);
}catch(BaseException e)
{
var res = new ResponseBase<PackageInfoDto?>(
code:e.code,
message:e.message,
data:null
);
return NotFound(res);
}
}
#endregion
#region
[HttpGet]
[Authorize(Roles = "User")]
public async Task<ActionResult<ResponseBase<List<PackageInfoDto>>>> GetPackageList(int pageIndex,int pageSize,bool desc)
{
var packageList = await packageService.GetAllPackagesAsync(pageIndex,pageSize,desc);
var res = new ResponseBase<List<PackageInfoDto>>(packageList);
return Ok(res);
}
#endregion
#region
[HttpGet]
[Authorize(Roles = "User")]
public async Task<ActionResult<ResponseBase<List<UserPackage>>>> GetUserPackageList(int pageIndex,int pageSize,bool desc)
{
var selfUserId = User.Claims.First(x => x.ValueType == "userId").Value;
var list = await packageService.GetUserPackagesAsync(int.Parse(selfUserId));
var res = new ResponseBase<List<UserPackage>>(list);
return Ok(res);
}
#endregion
#region
[HttpGet]
[Authorize(Roles = "Admin")]
public async Task<ActionResult<ResponseBase<List<UserPackage>>>> GetUserPackageListAdmin(int userId,int pageIndex, int pageSize, bool desc)
{
var list = await packageService.GetUserPackagesAsync(userId);
var res = new ResponseBase<List<UserPackage>>(list);
return Ok(res);
}
#endregion
#region
[HttpPost]
[Authorize(Roles = "User")]
public async Task<ActionResult<ResponseBase<UserPackage>>> UserPackageUpdate(int packageId,int day)
{
TimeSpan timeSpan = TimeSpan.FromDays(day);
var selfUserId = User.Claims.First(x => x.ValueType == "userId").Value;
var userPackage = await packageService.AddUserPackageTimeAsync(packageId,int.Parse(selfUserId),timeSpan,false);
var res = new ResponseBase<UserPackage>(userPackage);
return Ok(res);
}
#endregion
#region
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<ActionResult<ResponseBase<UserPackage>>> UserPackageUpdateAdmin(int packageId,int userId, int day)
{
TimeSpan timeSpan = TimeSpan.FromDays(day);
var userPackage = await packageService.AddUserPackageTimeAsync(packageId, userId, timeSpan, true);
var res = new ResponseBase<UserPackage>(userPackage);
return Ok(res);
}
#endregion
#region
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<ActionResult<ResponseBase<UserPackage?>>> DecuteUserPackage(int packageId,int userId,int day)
{
try
{
TimeSpan timeSpan = TimeSpan.FromDays(day);
var userPackage = await packageService.DecuteUserPackageTimeAsync(packageId, userId, timeSpan);
var res = new ResponseBase<UserPackage>(userPackage);
return Ok(res);
}catch(BaseException e)
{
var res = new ResponseBase<UserPackage?>(
code:e.code,
message:e.message,
data:null
);
return NotFound(res);
}
}
#endregion
}
}

View File

@ -0,0 +1,64 @@
using Apimanager_backend.Dtos;
using Apimanager_backend.Exceptions;
using Apimanager_backend.Models;
using Apimanager_backend.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Apimanager_backend.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class SystemConfigController : ControllerBase
{
private readonly ISystemConfigService systemConfigService;
private readonly ILogger<SystemConfigController> logger;
public SystemConfigController(ISystemConfigService systemConfigService, ILogger<SystemConfigController> logger)
{
this.systemConfigService = systemConfigService;
this.logger = logger;
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<ActionResult<ResponseBase<SystemConfig?>>> UpdateSystemConfig([FromBody]UpdateSystemConfigDto updateSystemConfigDto)
{
try
{
var configInfo = await systemConfigService.UpdateSystemConfig(updateSystemConfigDto.ConfigName, updateSystemConfigDto.ConfigBody);
var res = new ResponseBase<SystemConfig?>(configInfo);
return Ok(res);
}catch(BaseException e)
{
var res = new ResponseBase<SystemConfig?>(
code:e.code,
message:e.message,
data:null
);
return NotFound(res);
}
}
[HttpGet]
[Authorize(Roles = "User")]
public async Task<ActionResult<ResponseBase<SystemConfig?>>> GetSystemConfig(string configName)
{
try
{
var configInfo = await systemConfigService.GetSystemConfig(configName);
var res = new ResponseBase<SystemConfig?>(configInfo);
return Ok(res);
}
catch (BaseException e)
{
var res = new ResponseBase<SystemConfig?>(
code: e.code,
message: e.message,
data: null
);
return NotFound(res);
}
}
}
}

View File

@ -24,6 +24,8 @@ namespace Apimanager_backend.Data
public DbSet<UserRole> UserRoles { get; set; } public DbSet<UserRole> UserRoles { get; set; }
//日志表 //日志表
public DbSet<Log> Logs { get; set; } public DbSet<Log> Logs { get; set; }
//系统配置表
public DbSet<SystemConfig> SystemConfigs { get; set; }
public ApiContext(DbContextOptions<ApiContext> options) : base(options) { } public ApiContext(DbContextOptions<ApiContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
@ -31,6 +33,7 @@ namespace Apimanager_backend.Data
// 配置全局查询筛选器 // 配置全局查询筛选器
modelBuilder.Entity<User>().HasQueryFilter(u => !u.IsDelete); modelBuilder.Entity<User>().HasQueryFilter(u => !u.IsDelete);
modelBuilder.Entity<Api>().HasQueryFilter(a => !a.IsDelete); modelBuilder.Entity<Api>().HasQueryFilter(a => !a.IsDelete);
modelBuilder.Entity<Apipackage>().HasQueryFilter(x => x.IsDeleted);
//配置日志表 //配置日志表
modelBuilder.Entity<Log>().HasKey(x => x.Id); modelBuilder.Entity<Log>().HasKey(x => x.Id);
modelBuilder.Entity<Log>() modelBuilder.Entity<Log>()

View File

@ -0,0 +1,31 @@
using Apimanager_backend.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Newtonsoft.Json;
namespace Apimanager_backend.Data
{
public class SystemConfigConfig : IEntityTypeConfiguration<SystemConfig>
{
public void Configure(EntityTypeBuilder<SystemConfig> builder)
{
//主键
builder.HasKey(x => x.Id);
//自增
builder.Property(x => x.Id)
.ValueGeneratedOnAdd();
builder.HasData(
new SystemConfig(1,"SystemName", "青蓝"),
new SystemConfig(2,"SystemDescription", "描述"),
new SystemConfig(3,"LogoLocation", ""),
new SystemConfig(4,"FaviconLocation", ""),
new SystemConfig(5,"Phone","13000000000"),
new SystemConfig(6,"Email","admin@admin.com"),
new SystemConfig(
7,"RegisterConfig", JsonConvert.SerializeObject(new {RegisterOn = true,Emailvalidate = true })
)
);
}
}
}

View File

@ -18,6 +18,9 @@ namespace Apimanager_backend.Data
.IsUnique(); .IsUnique();
builder.HasIndex(x => x.Email) builder.HasIndex(x => x.Email)
.IsUnique(); .IsUnique();
builder.HasData(
new User(-1,"admin", "admin1@admin.com","e10adc3949ba59abbe56e057f20f883e")
);
} }
} }
} }

View File

@ -0,0 +1,8 @@
namespace Apimanager_backend.Dtos
{
public class UpdateSystemConfigDto
{
public string ConfigName { get; set; }
public string ConfigBody { get; set; }
}
}

View File

@ -0,0 +1,572 @@
// <auto-generated />
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("20241110134811_add-configTable")]
partial class addconfigTable
{
/// <inheritdoc />
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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Endpoint")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("IsActive")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsDelete")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsThirdParty")
.HasColumnType("tinyint(1)");
b.Property<int>("Method")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<int?>("PackageId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("PackageId");
b.ToTable("Apis");
});
modelBuilder.Entity("Apimanager_backend.Models.ApiCallLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("ApiId")
.HasColumnType("int");
b.Property<int>("CallResult")
.HasColumnType("int");
b.Property<DateTime>("CallTime")
.HasColumnType("datetime(6)");
b.Property<int>("UserId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ApiId");
b.HasIndex("UserId");
b.ToTable("CallLogs");
});
modelBuilder.Entity("Apimanager_backend.Models.ApiRequestExample", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("ApiId")
.HasColumnType("int");
b.Property<string>("Request")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Response")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("ResponseType")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ApiId");
b.ToTable("ApiRequestExample");
});
modelBuilder.Entity("Apimanager_backend.Models.Apipackage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("CallLimit")
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("IsDeleted")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.Property<int>("OneMinuteLimit")
.HasColumnType("int");
b.Property<decimal>("Price")
.HasColumnType("decimal(65,30)");
b.HasKey("Id");
b.ToTable("Apipackages");
});
modelBuilder.Entity("Apimanager_backend.Models.Log", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Exception")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("LogLevel")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Message")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("MessageTemplate")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Properties")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("Timestamp")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.ToTable("Logs");
});
modelBuilder.Entity("Apimanager_backend.Models.OperationLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("IpAddress")
.IsRequired()
.HasMaxLength(45)
.HasColumnType("varchar(45)");
b.Property<string>("Operation")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.Property<int>("TargetId")
.HasColumnType("int");
b.Property<string>("TargetType")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("varchar(50)");
b.Property<string>("UserAgent")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("UserId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("OperationLogs");
});
modelBuilder.Entity("Apimanager_backend.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<decimal>("Amount")
.HasColumnType("decimal(65,30)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasColumnType("longtext");
b.Property<string>("OrderNumber")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<int>("OrderType")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<string>("ThirdPartyOrderId")
.HasColumnType("varchar(255)");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.Property<int>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ConfigBody")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ApiKey")
.HasColumnType("longtext");
b.Property<decimal>("Balance")
.HasColumnType("decimal(65,30)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<bool>("IsBan")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsDelete")
.HasColumnType("tinyint(1)");
b.Property<string>("PassHash")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("varchar(255)");
b.Property<string>("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(2024, 11, 10, 13, 48, 10, 873, DateTimeKind.Utc).AddTicks(7811),
Email = "admin1@admin.com",
IsBan = false,
IsDelete = false,
PassHash = "e10adc3949ba59abbe56e057f20f883e",
Username = "admin"
});
});
modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("ExpiryDate")
.HasColumnType("datetime(6)");
b.Property<int>("PackageId")
.HasColumnType("int");
b.Property<DateTime>("PurchasedAt")
.HasColumnType("datetime(6)");
b.Property<int>("RemainingCalls")
.HasColumnType("int");
b.Property<int>("UserId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("PackageId");
b.HasIndex("UserId");
b.ToTable("UserPackages");
});
modelBuilder.Entity("Apimanager_backend.Models.UserRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Role")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("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
}
}
}

View File

@ -0,0 +1,99 @@
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
{
/// <inheritdoc />
public partial class addconfigTable : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ExpiryDate",
table: "Apipackages");
migrationBuilder.AddColumn<DateTime>(
name: "ExpiryDate",
table: "UserPackages",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<bool>(
name: "IsDeleted",
table: "Apipackages",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.CreateTable(
name: "SystemConfigs",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
ConfigName = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ConfigBody = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_SystemConfigs", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.InsertData(
table: "SystemConfigs",
columns: new[] { "Id", "ConfigBody", "ConfigName" },
values: new object[,]
{
{ 1, "青蓝", "SystemName" },
{ 2, "描述", "SystemDescription" },
{ 3, "", "LogoLocation" },
{ 4, "", "FaviconLocation" },
{ 5, "13000000000", "Phone" },
{ 6, "admin@admin.com", "Email" },
{ 7, "{\"RegisterOn\":true,\"Emailvalidate\":true}", "RegisterConfig" }
});
migrationBuilder.InsertData(
table: "Users",
columns: new[] { "Id", "ApiKey", "Balance", "CreatedAt", "Email", "IsBan", "IsDelete", "PassHash", "Username" },
values: new object[] { -1, null, 0m, new DateTime(2024, 11, 10, 13, 48, 10, 873, DateTimeKind.Utc).AddTicks(7811), "admin1@admin.com", false, false, "e10adc3949ba59abbe56e057f20f883e", "admin" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "SystemConfigs");
migrationBuilder.DeleteData(
table: "Users",
keyColumn: "Id",
keyValue: -1);
migrationBuilder.DropColumn(
name: "ExpiryDate",
table: "UserPackages");
migrationBuilder.DropColumn(
name: "IsDeleted",
table: "Apipackages");
migrationBuilder.AddColumn<DateTime>(
name: "ExpiryDate",
table: "Apipackages",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
}
}
}

View File

@ -130,8 +130,8 @@ namespace Apimanager_backend.Migrations
b.Property<DateTime>("CreatedAt") b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)"); .HasColumnType("datetime(6)");
b.Property<DateTime>("ExpiryDate") b.Property<bool>("IsDeleted")
.HasColumnType("datetime(6)"); .HasColumnType("tinyint(1)");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
@ -275,6 +275,69 @@ namespace Apimanager_backend.Migrations
b.ToTable("Orders"); b.ToTable("Orders");
}); });
modelBuilder.Entity("Apimanager_backend.Models.SystemConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ConfigBody")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("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 => modelBuilder.Entity("Apimanager_backend.Models.User", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -318,6 +381,19 @@ namespace Apimanager_backend.Migrations
.IsUnique(); .IsUnique();
b.ToTable("Users"); b.ToTable("Users");
b.HasData(
new
{
Id = -1,
Balance = 0m,
CreatedAt = new DateTime(2024, 11, 10, 13, 48, 10, 873, DateTimeKind.Utc).AddTicks(7811),
Email = "admin1@admin.com",
IsBan = false,
IsDelete = false,
PassHash = "e10adc3949ba59abbe56e057f20f883e",
Username = "admin"
});
}); });
modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b => modelBuilder.Entity("Apimanager_backend.Models.UserPackage", b =>
@ -326,6 +402,9 @@ namespace Apimanager_backend.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("int"); .HasColumnType("int");
b.Property<DateTime>("ExpiryDate")
.HasColumnType("datetime(6)");
b.Property<int>("PackageId") b.Property<int>("PackageId")
.HasColumnType("int"); .HasColumnType("int");

View File

@ -37,6 +37,10 @@ namespace Apimanager_backend.Models
/// 创建时间 /// 创建时间
/// </summary> /// </summary>
public DateTime CreatedAt { get; set; } = DateTime.UtcNow; // timestamp public DateTime CreatedAt { get; set; } = DateTime.UtcNow; // timestamp
/// <summary>
/// 是否删除
/// </summary>
public bool IsDeleted { get; set; } = false;
//导航属性 //导航属性
public ICollection<Api> Apis { get; set; } public ICollection<Api> Apis { get; set; }

View File

@ -0,0 +1,16 @@
namespace Apimanager_backend.Models
{
public class SystemConfig
{
public int Id { get; set; }
public string ConfigName { get; set; }
public string ConfigBody { get; set; }
public SystemConfig(int id,string configName,string configBody)
{
this.Id = id;
this.ConfigName = configName;
this.ConfigBody = configBody;
}
public SystemConfig() { }
}
}

View File

@ -61,5 +61,13 @@ namespace Apimanager_backend.Models
public ICollection<ApiCallLog> CallLogs { get; set; } public ICollection<ApiCallLog> CallLogs { get; set; }
public ICollection<Order> Orders { get; set; } public ICollection<Order> Orders { get; set; }
public ICollection<UserRole> Roles { get; set; } = new List<UserRole>(); public ICollection<UserRole> Roles { get; set; } = new List<UserRole>();
public User(int id,string username,string email,string passHash)
{
this.Id = id;
this.Username = username;
this.PassHash = passHash;
this.Email = email;
}
public User() { }
} }
} }

View File

@ -18,6 +18,7 @@ IConfiguration configuration = new ConfigurationBuilder()
string? redStr = configuration["Redis:ConnectionString"]; string? redStr = configuration["Redis:ConnectionString"];
string? constr = configuration.GetConnectionString("DefaultConnection"); string? constr = configuration.GetConnectionString("DefaultConnection");
//ÈÕÖ¾·þÎñ //ÈÕÖ¾·þÎñ
/*
Log.Logger = new LoggerConfiguration() Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug() .MinimumLevel.Debug()
.WriteTo.Console() .WriteTo.Console()
@ -27,7 +28,7 @@ Log.Logger = new LoggerConfiguration()
autoCreateTable:true autoCreateTable:true
).CreateLogger(); ).CreateLogger();
builder.Host.UseSerilog(); builder.Host.UseSerilog();
*/
builder.Services.AddDbContext<ApiContext>(option => builder.Services.AddDbContext<ApiContext>(option =>
option.UseMySql(constr, MySqlServerVersion.AutoDetect(constr)) option.UseMySql(constr, MySqlServerVersion.AutoDetect(constr))
); );
@ -61,6 +62,7 @@ if (app.Environment.IsDevelopment())
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseCors("AllowAll");
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();

View File

@ -67,7 +67,7 @@ namespace Apimanager_backend.Services
#region #region
public async Task<List<UserInfoDto>> GetUsersAsync(int page, int pageSize, bool desc) public async Task<List<UserInfoDto>> GetUsersAsync(int page, int pageSize, bool desc)
{ {
var query = context.Users.Where(x => true) var query = context.Users.Include(x => x.Roles).Where(x => true)
.OrderBy(x => x.Id); .OrderBy(x => x.Id);
//倒序 //倒序
if (desc) if (desc)

View File

@ -1,4 +1,5 @@
using Apimanager_backend.Dtos; using Apimanager_backend.Dtos;
using Apimanager_backend.Models;
namespace Apimanager_backend.Services namespace Apimanager_backend.Services
{ {
@ -37,6 +38,27 @@ namespace Apimanager_backend.Services
/// <param name="packageId"></param> /// <param name="packageId"></param>
/// <returns></returns> /// <returns></returns>
public Task<PackageInfoDto> PackageInfoByIdAsync(int packageId); public Task<PackageInfoDto> PackageInfoByIdAsync(int packageId);
/// <summary>
/// 获取用户所有订阅套餐
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public Task<List<UserPackage>> GetUserPackagesAsync(int userId);
/// <summary>
/// 增加套餐订阅时长
/// </summary>
/// <param name="packageId">套餐Id注意这里不是用户订阅套餐表的Id</param>
/// <param name="time"></param>
/// <param name="isAdmin">判断是否为管理员操作(如果是则不扣除余额)</param>
/// <returns></returns>
public Task<UserPackage> AddUserPackageTimeAsync(int packageId,int userId,TimeSpan time,bool isAdmin);
/// <summary>
/// 扣除套餐订阅时长
/// </summary>
/// <param name="packageId">套餐Id注意这里不是用户订阅套餐表的Id</param>
/// <param name="time"></param>
/// <returns></returns>
public Task<UserPackage> DecuteUserPackageTimeAsync(int packageId,int userId,TimeSpan time);
} }

View File

@ -0,0 +1,10 @@
using Apimanager_backend.Models;
namespace Apimanager_backend.Services
{
public interface ISystemConfigService
{
public Task<SystemConfig> UpdateSystemConfig(string configName,string configBody);
public Task<SystemConfig> GetSystemConfig(string configName);
}
}

View File

@ -0,0 +1,201 @@
using Apimanager_backend.Data;
using Apimanager_backend.Dtos;
using Apimanager_backend.Exceptions;
using Apimanager_backend.Models;
using AutoMapper;
using AutoMapper.Configuration.Annotations;
using Microsoft.EntityFrameworkCore;
namespace Apimanager_backend.Services
{
public class PackageService : IPackageService
{
private readonly ApiContext apiContext;
private readonly ILogger<PackageService> logger;
private readonly IMapper mapper;
public PackageService(ApiContext apiContext,ILogger<PackageService> logger,IMapper mapper)
{
this.apiContext = apiContext;
this.logger = logger;
this.mapper = mapper;
}
#region
public async Task<PackageInfoDto> AddPackageAsync(AddPackageDto addPackageDto)
{
var packageInfo = mapper.Map<Apipackage>(addPackageDto);
apiContext.Apipackages.Add(packageInfo);
await apiContext.SaveChangesAsync();
return mapper.Map<PackageInfoDto>(packageInfo);
}
#endregion
#region
public async Task<UserPackage> AddUserPackageTimeAsync(int packageId,int userId,TimeSpan time,bool isAdmin)
{
await using var transaction = await apiContext.Database.BeginTransactionAsync();
try
{
//查询用户名下有无对应套餐
var userPackageInfo = await apiContext.UserPackages.FirstOrDefaultAsync(
x => x.PackageId == packageId && x.UserId == userId
);
//查询套餐是否存在
var packageInfo = await apiContext.Apipackages.FirstOrDefaultAsync(x => x.Id == packageId);
if (packageInfo == null)
{
throw new BaseException(4004,"套餐不存在");
}
//查询用户是否存在
var user = await apiContext.Users.FirstOrDefaultAsync(x => x.Id == userId);
if (user == null)
{
throw new BaseException(2004,"用户不存在");
}
//如果没有对应套餐关联则新建
if (userPackageInfo == null)
{
userPackageInfo = new UserPackage
{
PackageId = packageId,
UserId = userId,
ExpiryDate = DateTime.UtcNow + time,
};
apiContext.UserPackages.Add(userPackageInfo);
}
else
{
//否则直接在关联记录上添加有效期
userPackageInfo.ExpiryDate += time;
apiContext.UserPackages.Update(userPackageInfo);
}
if (!isAdmin)
{
//扣除对应用户余额
user.Balance -= packageInfo.Price * time.Days;
apiContext.Users.Update(user);
}
await apiContext.SaveChangesAsync();
await transaction.CommitAsync();
return userPackageInfo;
} catch (Exception)
{
await transaction.RollbackAsync();
throw;
}
}
#endregion
#region
public async Task<UserPackage> DecuteUserPackageTimeAsync(int packageId,int userId, TimeSpan time)
{
await using var transaction = await apiContext.Database.BeginTransactionAsync();
try
{
//查询用户名下有无对应套餐
var userPackageInfo = await apiContext.UserPackages.FirstOrDefaultAsync(
x => x.PackageId == packageId && x.UserId == userId
);
//如果没有对应套餐则返回错误信息
if (userPackageInfo == null)
{
throw new BaseException(4004,"套餐未找到");
}
//否则直接在关联记录上添加有效期
userPackageInfo.ExpiryDate -= time;
apiContext.UserPackages.Update(userPackageInfo);
await apiContext.SaveChangesAsync();
await transaction.CommitAsync();
return userPackageInfo;
}
catch (Exception)
{
await transaction.RollbackAsync();
throw;
}
}
#endregion
#region
public async Task DeletePackageAsync(int packageId)
{
await using var transaction = await apiContext.Database.BeginTransactionAsync();
try
{
var packageInfo = await apiContext.Apipackages.FirstOrDefaultAsync(x => x.Id == packageId);
if (packageInfo == null)
{
throw new BaseException(4004, "套餐未找到");
}
packageInfo.IsDeleted = true;
apiContext.Apipackages.Update(packageInfo);
await apiContext.SaveChangesAsync();
await transaction.CommitAsync();
}catch(Exception)
{
transaction.Rollback();
throw;
}
}
#endregion
#region
public async Task<List<PackageInfoDto>> GetAllPackagesAsync(int pageIndex, int pageSize, bool desc)
{
IQueryable<Apipackage> query = apiContext.Apipackages.Where(x => true).OrderBy(x => x.Id);
if(desc)
{
query = query.OrderDescending();
}
query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
var list = await query.ToListAsync();
return mapper.Map<List<PackageInfoDto>>(list);
}
#endregion
#region
public async Task<List<UserPackage>> GetUserPackagesAsync(int userId)
{
var userpackageInfo = await apiContext.UserPackages.Where(x => x.UserId == userId).ToListAsync();
return userpackageInfo;
}
#endregion
#region
public async Task<PackageInfoDto> PackageInfoByIdAsync(int packageId)
{
var packageInfo = await apiContext.Apipackages.FirstOrDefaultAsync(x => x.Id == packageId);
if(packageInfo == null)
{
throw new BaseException(4004,"套餐未找到");
}
return mapper.Map<PackageInfoDto>(packageInfo);
}
#endregion
#region
public async Task<PackageInfoDto> UpdatePackageAsync(int packageId, UpdatePackageDto updatePackageDto)
{
await using var transaction = await apiContext.Database.BeginTransactionAsync();
try
{
//查询对应套餐
var packageInfo = await apiContext.Apipackages.FirstOrDefaultAsync(x => x.Id == packageId);
if (packageInfo == null)
{
throw new BaseException(4004, "Success");
}
//更新字段
packageInfo.Name = updatePackageDto.Name ?? packageInfo.Name;
packageInfo.CallLimit = updatePackageDto.CallLimit != null ? updatePackageDto.CallLimit.Value : packageInfo.CallLimit;
packageInfo.OneMinuteLimit = updatePackageDto.OneMinuteLimit != null ? updatePackageDto.OneMinuteLimit.Value : packageInfo.OneMinuteLimit;
packageInfo.Price = updatePackageDto.Price != null ? updatePackageDto.Price.Value : packageInfo.Price;
//更新
apiContext.Apipackages.Update(packageInfo);
await apiContext.SaveChangesAsync();
await transaction.CommitAsync();
return mapper.Map<PackageInfoDto>(packageInfo);
}
catch (Exception)
{
await transaction.RollbackAsync();
throw;
}
}
#endregion
}
}

View File

@ -0,0 +1,40 @@

using Apimanager_backend.Data;
using Apimanager_backend.Exceptions;
using Apimanager_backend.Models;
using Microsoft.EntityFrameworkCore;
namespace Apimanager_backend.Services
{
public class SystemConfigService : ISystemConfigService
{
private readonly ApiContext apiContext;
private readonly ILogger<SystemConfigService> logger;
public SystemConfigService(ApiContext apiContext,ILogger<SystemConfigService> logger)
{
this.apiContext = apiContext;
this.logger = logger;
}
public async Task<SystemConfig> UpdateSystemConfig(string configName, string configBody)
{
var config = await apiContext.SystemConfigs.FirstOrDefaultAsync(x => x.ConfigName == configName);
if (config == null)
{
throw new BaseException(5006,"配置不存在");
}
config.ConfigBody = configBody;
apiContext.SystemConfigs.Update(config);
await apiContext.SaveChangesAsync();
return config;
}
public async Task<SystemConfig> GetSystemConfig(string configName)
{
var config = await apiContext.SystemConfigs.FirstOrDefaultAsync(x => x.ConfigName == configName);
if (config == null)
{
throw new BaseException(5006, "配置不存在");
}
return config;
}
}
}

View File

@ -31,7 +31,7 @@ namespace Apimanager_backend.Services
} }
public async Task<UserInfoDto> GetUserAsync(int userId) public async Task<UserInfoDto> GetUserAsync(int userId)
{ {
User? user = await apiContext.Users.SingleOrDefaultAsync(x => x.Id == userId); User? user = await apiContext.Users.Include(x => x.Roles).SingleOrDefaultAsync(x => x.Id == userId);
//未找到用户 //未找到用户
if (user == null) if (user == null)
{ {

View File

@ -7,7 +7,7 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnection": "server=192.168.5.200;username=root;password=768788Dyw@;port=3306;database=api_billing_system;SslMode=Preferred;" "DefaultConnection": "server=192.168.5.100;username=root;password=768788dyw;port=3306;database=api_billing_system;SslMode=Preferred;"
}, },
"JwtSettings": { "JwtSettings": {
"Secret": "deXtdXode6hv0SI1o6xRw1ALkn0vYsWn", "Secret": "deXtdXode6hv0SI1o6xRw1ALkn0vYsWn",
@ -17,7 +17,7 @@
"RefreshTokenExpiryDays": 7 "RefreshTokenExpiryDays": 7
}, },
"redis": { "redis": {
"ConnectionString": "192.168.5.200:6379" "ConnectionString": "192.168.5.100:6379"
}, },
"EmailSettings": { "EmailSettings": {
"Server": "smtp.exmail.qq.com", "Server": "smtp.exmail.qq.com",

View File

@ -46,9 +46,10 @@
| 4001 | 400 | 支付请求无效 | Invalid payment request | | 4001 | 400 | 支付请求无效 | Invalid payment request |
| 4002 | 402 | 支付失败,余额不足 | Payment failed, insufficient balance | | 4002 | 402 | 支付失败,余额不足 | Payment failed, insufficient balance |
| 4003 | 404 | 订单未找到 | Order not found | | 4003 | 404 | 订单未找到 | Order not found |
| 4004 | 409 | 重复支付或订单冲突 | Duplicate payment or order conflict | | 4004 | 404 | 套餐未找到 | Package not found |
| 4005 | 500 | 支付系统错误 | Payment system error | | 4005 | 409 | 重复支付或订单冲突 | Duplicate payment or order conflict |
| 4006 | 200 | 退款成功 | Refund successful | | 4006 | 500 | 支付系统错误 | Payment system error |
| 4007 | 200 | 退款成功 | Refund successful |
#### 日志与系统模块错误码5xxx #### 日志与系统模块错误码5xxx
@ -59,4 +60,5 @@
| 5002 | 500 | 日志服务异常 | Log service error | | 5002 | 500 | 日志服务异常 | Log service error |
| 5003 | 403 | 无权限查看操作日志 | No permission to view logs | | 5003 | 403 | 无权限查看操作日志 | No permission to view logs |
| 5004 | 500 | 邮件发送错误 | Email send error | | 5004 | 500 | 邮件发送错误 | Email send error |
| 5005 | 400 | 验证码错误 | ValidateCode Error | | 5005 | 400 | 验证码错误 | ValidateCode Error |
| 5006 | 404 | 配置不存在 | Config not found |