| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- using System.Text.RegularExpressions;
- using Application.Abstractions.Data;
- using Application.Abstractions.Messaging;
- using Microsoft.EntityFrameworkCore;
- using SharedKernel.Results;
- namespace Application.Features.Api.Studio.IssueDonationCode;
- internal sealed class Handler(IAppDbContext db) : ICommandHandler<Command, Result<Response>>
- {
- public async Task<Result<Response>> Handle(Command request, CancellationToken ct)
- {
- if (string.IsNullOrWhiteSpace(request.Code))
- {
- return Result.Failure<Response>(Error.Problem("DonationCode.Required", "후원 코드를 입력해 주세요."));
- }
- var trimmed = request.Code.Trim();
- if (!Regex.IsMatch(trimmed, "^[A-Za-z0-9]{4,7}$"))
- {
- return Result.Failure<Response>(Error.Problem("DonationCode.InvalidFormat", "후원 코드는 4~7자 영문/숫자만 가능합니다."));
- }
- var channel = await db.Channel.FirstOrDefaultAsync(c => c.MemberID == request.MemberID && c.IsActive, ct);
- if (channel is null)
- {
- return Result.Failure<Response>(Error.NotFound("Channel.NotFound", "활성 채널을 찾을 수 없습니다."));
- }
- if (channel.DonationCode is not null)
- {
- return Result.Failure<Response>(Error.Conflict("DonationCode.AlreadyIssued", "이미 후원 코드가 발급되어 변경할 수 없습니다."));
- }
- var normalized = trimmed.ToUpperInvariant();
- var duplicate = await db.Channel.AsNoTracking().AnyAsync(c => c.DonationCode == normalized, ct);
- if (duplicate)
- {
- return Result.Failure<Response>(Error.Conflict("DonationCode.Duplicate", "이미 사용 중인 후원 코드입니다. 다른 코드를 시도해 주세요."));
- }
- try
- {
- channel.IssueDonationCode(normalized);
- await db.SaveChangesAsync(ct);
- }
- catch (DbUpdateException)
- {
- return Result.Failure<Response>(Error.Conflict("DonationCode.Duplicate", "이미 사용 중인 후원 코드입니다. 다른 코드를 시도해 주세요."));
- }
- return Result.Success(new Response(channel.DonationCode!));
- }
- }
|