feat(risk-control): add FastEndpoints APIs
This commit is contained in:
parent
2b85e2d115
commit
1ac028643f
100
Fengling.RiskControl.Web/Endpoints/LotteryEndpoints.cs
Normal file
100
Fengling.RiskControl.Web/Endpoints/LotteryEndpoints.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
using FastEndpoints;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Fengling.RiskControl.Application.Services;
|
||||||
|
using Fengling.RiskControl.Domain.Aggregates.LotteryActivities;
|
||||||
|
|
||||||
|
namespace Fengling.RiskControl.Web.Endpoints;
|
||||||
|
|
||||||
|
public class ParticipateLotteryEndpoint : Endpoint<ParticipateLotteryRequest, LotteryParticipationResult>
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public ParticipateLotteryEndpoint(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Post("/api/v1/lottery/participate");
|
||||||
|
Summary(s => {
|
||||||
|
s.Summary = "参与抽奖";
|
||||||
|
s.Description = "会员参与抽奖活动,系统自动进行风险评估";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(ParticipateLotteryRequest req, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var result = await _mediator.Send(new LotteryParticipationRequest
|
||||||
|
{
|
||||||
|
MemberId = req.MemberId,
|
||||||
|
ActivityType = req.ActivityType,
|
||||||
|
StakePoints = req.StakePoints,
|
||||||
|
IpAddress = HttpContext.Connection.RemoteIpAddress?.ToString(),
|
||||||
|
DeviceId = HttpContext.Request.Headers["X-Device-ID"].FirstOrDefault()
|
||||||
|
}, ct);
|
||||||
|
|
||||||
|
Response = (LotteryParticipationResult)result!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParticipateLotteryRequest
|
||||||
|
{
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public long MemberId { get; set; }
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public string ActivityType { get; set; } = string.Empty;
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public int StakePoints { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GetLotteryHistoryEndpoint : Endpoint<GetLotteryHistoryRequest, IEnumerable<LotteryActivityResponse>>
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public GetLotteryHistoryEndpoint(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Get("/api/v1/lottery/history/{MemberId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(GetLotteryHistoryRequest req, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var activities = await _mediator.Send(new GetMemberLotteriesQuery { MemberId = req.MemberId }, ct);
|
||||||
|
Response = activities.Select(a => new LotteryActivityResponse
|
||||||
|
{
|
||||||
|
Id = a.Id,
|
||||||
|
ActivityType = a.ActivityType,
|
||||||
|
StakePoints = a.StakePoints,
|
||||||
|
WinAmount = a.WinAmount,
|
||||||
|
Status = a.Status.ToString(),
|
||||||
|
CreatedAt = a.CreatedAt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GetLotteryHistoryRequest
|
||||||
|
{
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromRoute]
|
||||||
|
public long MemberId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record GetMemberLotteriesQuery : IRequest<IEnumerable<LotteryActivityResponse>>
|
||||||
|
{
|
||||||
|
public long MemberId { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record LotteryActivityResponse
|
||||||
|
{
|
||||||
|
public long Id { get; init; }
|
||||||
|
public string ActivityType { get; init; } = string.Empty;
|
||||||
|
public int StakePoints { get; init; }
|
||||||
|
public int? WinAmount { get; init; }
|
||||||
|
public string Status { get; init; } = string.Empty;
|
||||||
|
public DateTime CreatedAt { get; init; }
|
||||||
|
}
|
||||||
102
Fengling.RiskControl.Web/Endpoints/RiskAlertEndpoints.cs
Normal file
102
Fengling.RiskControl.Web/Endpoints/RiskAlertEndpoints.cs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
using FastEndpoints;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Fengling.RiskControl.Domain.Aggregates.RiskAlerts;
|
||||||
|
|
||||||
|
namespace Fengling.RiskControl.Web.Endpoints;
|
||||||
|
|
||||||
|
public class GetPendingAlertsEndpoint : Endpoint<EmptyRequest, IEnumerable<RiskAlertResponse>>
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public GetPendingAlertsEndpoint(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Get("/api/v1/risk/alerts/pending");
|
||||||
|
Roles("Admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(EmptyRequest req, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var alerts = await _mediator.Send(new GetPendingAlertsQuery(), ct);
|
||||||
|
Response = alerts.Select(a => new RiskAlertResponse
|
||||||
|
{
|
||||||
|
Id = a.Id,
|
||||||
|
MemberId = a.MemberId,
|
||||||
|
AlertType = a.AlertType,
|
||||||
|
Description = a.Description,
|
||||||
|
Priority = a.Priority.ToString(),
|
||||||
|
Status = a.Status.ToString(),
|
||||||
|
CreatedAt = a.CreatedAt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GetPendingAlertsQuery : IRequest<IEnumerable<RiskAlert>>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RiskAlertResponse
|
||||||
|
{
|
||||||
|
public long Id { get; init; }
|
||||||
|
public long MemberId { get; init; }
|
||||||
|
public string AlertType { get; init; } = string.Empty;
|
||||||
|
public string Description { get; init; } = string.Empty;
|
||||||
|
public string Priority { get; init; } = string.Empty;
|
||||||
|
public string Status { get; init; } = string.Empty;
|
||||||
|
public DateTime CreatedAt { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResolveAlertEndpoint : Endpoint<ResolveAlertRequest, RiskAlertResponse>
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public ResolveAlertEndpoint(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Post("/api/v1/risk/alerts/{AlertId}/resolve");
|
||||||
|
Roles("Admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(ResolveAlertRequest req, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var alert = await _mediator.Send(new ResolveAlertCommand
|
||||||
|
{
|
||||||
|
AlertId = req.AlertId,
|
||||||
|
Notes = req.Notes
|
||||||
|
}, ct);
|
||||||
|
|
||||||
|
Response = new RiskAlertResponse
|
||||||
|
{
|
||||||
|
Id = alert.Id,
|
||||||
|
MemberId = alert.MemberId,
|
||||||
|
AlertType = alert.AlertType,
|
||||||
|
Description = alert.Description,
|
||||||
|
Priority = alert.Priority.ToString(),
|
||||||
|
Status = alert.Status.ToString(),
|
||||||
|
CreatedAt = alert.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResolveAlertRequest
|
||||||
|
{
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromRoute]
|
||||||
|
public long AlertId { get; set; }
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public string Notes { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ResolveAlertCommand : IRequest<RiskAlert>
|
||||||
|
{
|
||||||
|
public long AlertId { get; init; }
|
||||||
|
public string Notes { get; init; } = string.Empty;
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
using FastEndpoints;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Fengling.RiskControl.Application.Services;
|
||||||
|
using Fengling.RiskControl.Application.Commands;
|
||||||
|
|
||||||
|
namespace Fengling.RiskControl.Web.Endpoints;
|
||||||
|
|
||||||
|
public class EvaluateRiskEndpoint : Endpoint<EvaluateRiskRequest, RiskEvaluationResult>
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public EvaluateRiskEndpoint(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Post("/api/v1/risk/evaluate");
|
||||||
|
Summary(s => {
|
||||||
|
s.Summary = "风险评估";
|
||||||
|
s.Description = "对会员进行实时风险评估";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(EvaluateRiskRequest req, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var result = await _mediator.Send(new EvaluateRiskCommand
|
||||||
|
{
|
||||||
|
MemberId = req.MemberId,
|
||||||
|
EntityType = req.EntityType,
|
||||||
|
EntityId = req.EntityId,
|
||||||
|
ActionType = req.ActionType,
|
||||||
|
Context = req.Context ?? new()
|
||||||
|
}, ct);
|
||||||
|
|
||||||
|
Response = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EvaluateRiskRequest
|
||||||
|
{
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public long MemberId { get; set; }
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public string EntityType { get; set; } = string.Empty;
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public string EntityId { get; set; } = string.Empty;
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public string ActionType { get; set; } = string.Empty;
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public Dictionary<string, object>? Context { get; set; }
|
||||||
|
}
|
||||||
83
Fengling.RiskControl.Web/Endpoints/RiskRuleEndpoints.cs
Normal file
83
Fengling.RiskControl.Web/Endpoints/RiskRuleEndpoints.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using FastEndpoints;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Fengling.RiskControl.Domain.Aggregates.RiskRules;
|
||||||
|
|
||||||
|
namespace Fengling.RiskControl.Web.Endpoints;
|
||||||
|
|
||||||
|
public class CreateRiskRuleEndpoint : Endpoint<CreateRiskRuleRequest, RiskRuleResponse>
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public CreateRiskRuleEndpoint(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Configure()
|
||||||
|
{
|
||||||
|
Post("/api/v1/risk/rules");
|
||||||
|
Roles("Admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task HandleAsync(CreateRiskRuleRequest req, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var rule = await _mediator.Send(new CreateRiskRuleCommand
|
||||||
|
{
|
||||||
|
Name = req.Name,
|
||||||
|
Description = req.Description,
|
||||||
|
RuleType = (RiskRuleType)req.RuleType,
|
||||||
|
Action = (RiskRuleAction)req.Action,
|
||||||
|
ConfigJson = req.ConfigJson,
|
||||||
|
Priority = req.Priority
|
||||||
|
}, ct);
|
||||||
|
|
||||||
|
Response = new RiskRuleResponse
|
||||||
|
{
|
||||||
|
Id = rule.Id,
|
||||||
|
Name = rule.Name,
|
||||||
|
Description = rule.Description,
|
||||||
|
RuleType = ((int)rule.RuleType).ToString(),
|
||||||
|
Action = ((int)rule.Action).ToString(),
|
||||||
|
IsActive = rule.IsActive,
|
||||||
|
CreatedAt = rule.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CreateRiskRuleRequest
|
||||||
|
{
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public int RuleType { get; set; }
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public int Action { get; set; }
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public string ConfigJson { get; set; } = string.Empty;
|
||||||
|
[Microsoft.AspNetCore.Mvc.FromBody]
|
||||||
|
public int Priority { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record CreateRiskRuleCommand : IRequest<RiskRule>
|
||||||
|
{
|
||||||
|
public string Name { get; init; } = string.Empty;
|
||||||
|
public string Description { get; init; } = string.Empty;
|
||||||
|
public RiskRuleType RuleType { get; init; }
|
||||||
|
public RiskRuleAction Action { get; init; }
|
||||||
|
public string ConfigJson { get; init; } = string.Empty;
|
||||||
|
public int Priority { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RiskRuleResponse
|
||||||
|
{
|
||||||
|
public long Id { get; init; }
|
||||||
|
public string Name { get; init; } = string.Empty;
|
||||||
|
public string Description { get; init; } = string.Empty;
|
||||||
|
public string RuleType { get; init; } = string.Empty;
|
||||||
|
public string Action { get; init; } = string.Empty;
|
||||||
|
public bool IsActive { get; init; }
|
||||||
|
public DateTime CreatedAt { get; init; }
|
||||||
|
}
|
||||||
@ -1,7 +1,46 @@
|
|||||||
|
using Fengling.RiskControl.Infrastructure;
|
||||||
|
using Fengling.RiskControl.Infrastructure.Repositories;
|
||||||
|
using Fengling.RiskControl.Domain.Repositories;
|
||||||
|
using Fengling.RiskControl.Domain.Aggregates.RiskRules;
|
||||||
|
using Fengling.RiskControl.Domain.Aggregates.RiskScores;
|
||||||
|
using Fengling.RiskControl.Domain.Aggregates.RiskAlerts;
|
||||||
|
using Fengling.RiskControl.Domain.Aggregates.LotteryActivities;
|
||||||
|
using Fengling.RiskControl.Application.Services;
|
||||||
|
using FastEndpoints;
|
||||||
|
using FluentValidation;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddFastEndpoints();
|
||||||
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
builder.Services.AddDbContext<RiskControlDbContext>(options =>
|
||||||
|
options.UseNpgsql(builder.Configuration.GetConnectionString("RiskControl")));
|
||||||
|
|
||||||
|
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
|
||||||
|
builder.Services.AddValidatorsFromAssemblyContaining<Program>(lifetime: ServiceLifetime.Scoped);
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IRiskRuleRepository, RiskRuleRepository>();
|
||||||
|
builder.Services.AddScoped<IRiskScoreRepository, RiskScoreRepository>();
|
||||||
|
builder.Services.AddScoped<IRiskAlertRepository, RiskAlertRepository>();
|
||||||
|
builder.Services.AddScoped<ILotteryActivityRepository, LotteryActivityRepository>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IRiskEvaluationService, RiskEvaluationService>();
|
||||||
|
builder.Services.AddScoped<ILotteryService, LotteryService>();
|
||||||
|
builder.Services.AddScoped<IRiskAlertService, RiskAlertService>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.MapGet("/", () => "Fengling RiskControl Service");
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseFastEndpoints();
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user