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);
|
||||
|
||||
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();
|
||||
|
||||
app.MapGet("/", () => "Fengling RiskControl Service");
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseFastEndpoints();
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.Run();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user