remove Features-directory and move the files to the root directory

This commit is contained in:
2026-07-15 15:03:12 +02:00
parent bfe24eba06
commit 8f2365d048
21 changed files with 27 additions and 27 deletions

View File

@@ -0,0 +1,36 @@
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
using DigitalData.EmailProfiler.Domain.Entities;
using MediatR;
namespace DigitalData.EmailProfiler.Application.EmailAccounts.Commands;
/// <summary>
/// Command to create a new email account.
/// </summary>
public record CreateEmailAccountCommand : IRequest<int>
{
public string AccountName { get; init; } = string.Empty;
public string Username { get; init; } = string.Empty;
public string ImapServer { get; init; } = string.Empty;
public int ImapPort { get; init; } = 993;
public bool ImapUseSsl { get; init; } = true;
public string SmtpServer { get; init; } = string.Empty;
public int SmtpPort { get; init; } = 587;
public bool SmtpUseSsl { get; init; } = true;
public bool UseOAuth2 { get; init; }
public string? EncryptedPassword { get; init; } // Already encrypted by client
public string? TenantId { get; init; }
public string? ClientId { get; init; }
public string? EncryptedClientSecret { get; init; } // Already encrypted by client
public bool IsActive { get; init; } = true;
}
public class CreateEmailAccountCommandHandler(IRepository<EmailAccount> repository)
: IRequestHandler<CreateEmailAccountCommand, int>
{
public async Task<int> Handle(CreateEmailAccountCommand request, CancellationToken cancellationToken)
{
var account = await repository.CreateAsync(request, cancellationToken);
return account.Id;
}
}

View File

@@ -0,0 +1,26 @@
using AutoMapper;
using DigitalData.EmailProfiler.Application.Common.Dtos;
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
using DigitalData.EmailProfiler.Domain.Entities;
using MediatR;
namespace DigitalData.EmailProfiler.Application.EmailAccounts.Queries;
/// <summary>
/// Query to get email account by ID.
/// </summary>
public record GetEmailAccountByIdQuery(int Id) : IRequest<EmailAccountDto?>;
public class GetEmailAccountByIdQueryHandler(
IRepository<EmailAccount> repository,
IMapper mapper)
: IRequestHandler<GetEmailAccountByIdQuery, EmailAccountDto?>
{
public async Task<EmailAccountDto?> Handle(
GetEmailAccountByIdQuery request,
CancellationToken cancellationToken)
{
var account = await repository.GetByIdAsync(request.Id, cancellationToken);
return account != null ? mapper.Map<EmailAccountDto>(account) : null;
}
}

View File

@@ -0,0 +1,26 @@
using AutoMapper;
using DigitalData.EmailProfiler.Application.Common.Dtos;
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
using DigitalData.EmailProfiler.Domain.Entities;
using MediatR;
namespace DigitalData.EmailProfiler.Application.EmailAccounts.Queries;
/// <summary>
/// Query to get all email accounts.
/// </summary>
public record GetEmailAccountsQuery : IRequest<IEnumerable<EmailAccountDto>>;
public class GetEmailAccountsQueryHandler(
IRepository<EmailAccount> repository,
IMapper mapper)
: IRequestHandler<GetEmailAccountsQuery, IEnumerable<EmailAccountDto>>
{
public async Task<IEnumerable<EmailAccountDto>> Handle(
GetEmailAccountsQuery request,
CancellationToken cancellationToken)
{
var accounts = await repository.GetAllAsync(cancellationToken);
return mapper.Map<IEnumerable<EmailAccountDto>>(accounts);
}
}

View File

@@ -0,0 +1,56 @@
using DigitalData.EmailProfiler.Application.EmailAccounts.Commands;
using FluentValidation;
namespace DigitalData.EmailProfiler.Application.EmailAccounts.Validators;
/// <summary>
/// Validator for CreateEmailAccountCommand.
/// </summary>
public class CreateEmailAccountCommandValidator : AbstractValidator<CreateEmailAccountCommand>
{
public CreateEmailAccountCommandValidator()
{
RuleFor(x => x.AccountName)
.NotEmpty().WithMessage("Account name is required")
.MaximumLength(100).WithMessage("Account name must not exceed 100 characters");
RuleFor(x => x.Username)
.NotEmpty().WithMessage("Username is required")
.MaximumLength(200).WithMessage("Username must not exceed 200 characters")
.EmailAddress().WithMessage("Username must be a valid email address");
RuleFor(x => x.ImapServer)
.NotEmpty().WithMessage("IMAP server is required")
.MaximumLength(200).WithMessage("IMAP server must not exceed 200 characters");
RuleFor(x => x.ImapPort)
.GreaterThan(0).WithMessage("IMAP port must be greater than 0")
.LessThanOrEqualTo(65535).WithMessage("IMAP port must not exceed 65535");
RuleFor(x => x.SmtpServer)
.NotEmpty().WithMessage("SMTP server is required")
.MaximumLength(200).WithMessage("SMTP server must not exceed 200 characters");
RuleFor(x => x.SmtpPort)
.GreaterThan(0).WithMessage("SMTP port must be greater than 0")
.LessThanOrEqualTo(65535).WithMessage("SMTP port must not exceed 65535");
// OAuth2 validation
RuleFor(x => x.TenantId)
.NotEmpty().WithMessage("Tenant ID is required for OAuth2")
.When(x => x.UseOAuth2);
RuleFor(x => x.ClientId)
.NotEmpty().WithMessage("Client ID is required for OAuth2")
.When(x => x.UseOAuth2);
RuleFor(x => x.EncryptedClientSecret)
.NotEmpty().WithMessage("Client secret is required for OAuth2")
.When(x => x.UseOAuth2);
// Password validation (non-OAuth2)
RuleFor(x => x.EncryptedPassword)
.NotEmpty().WithMessage("Password is required")
.When(x => !x.UseOAuth2);
}
}