using MediatR; using FluentValidation; using Fengling.Member.Domain.Aggregates.Users; using Fengling.Member.Infrastructure.Repositories; namespace Fengling.Member.Application.Commands.Member; public record BindOAuthCommand(OAuthProvider Provider, MemberId MemberId, string OpenId, string? UnionId) : IRequest; public record BindOAuthResponse(MemberId MemberId, OAuthProvider Provider, string OpenId, string? UnionId, DateTime BoundAt); public class BindOAuthCommandValidator : AbstractValidator { public BindOAuthCommandValidator() { RuleFor(x => x.Provider).IsInEnum(); RuleFor(x => x.OpenId).NotEmpty().MaximumLength(128); RuleFor(x => x.UnionId).MaximumLength(128); } } public class BindOAuthCommandHandler(IMemberRepository memberRepository, ILogger logger) : IRequestHandler { public async Task Handle(BindOAuthCommand request, CancellationToken cancellationToken) { logger.LogInformation("Binding {Provider} for member {MemberId}", request.Provider.GetProviderName(), request.MemberId); var member = await memberRepository.GetAsync(request.MemberId, cancellationToken) ?? throw new KeyNotFoundException($"会员不存在: {request.MemberId}"); member.BindOAuth(request.Provider, request.OpenId, request.UnionId); logger.LogInformation("{Provider} bound successfully for member {MemberId}", request.Provider.GetProviderName(), request.MemberId); return new BindOAuthResponse(member.Id, request.Provider, request.OpenId, request.UnionId, DateTime.UtcNow); } }