Refactor MediatR commands and update solution structure
- Consolidated commands and handlers into single files for better organization. - Updated file naming conventions for commands and queries. - Added explicit Git operation rules to prevent automatic commits/pushes. - Introduced new projects and restructured solution file (`legacy` folder). - Refactored `CreateEmailAccountCommand`, `ProcessEmailCommand`, and others to use `IUnitOfWork`. - Enhanced `ProcessEmailCommandHandler` with attachment validation and error handling. - Removed redundant handler files after consolidation. - Improved code consistency and added `TODO` comments for future enhancements.
This commit is contained in:
@@ -55,8 +55,32 @@ var lastPoll = DateTime.UtcNow.AddMinutes(-profile.PollIntervalMinutes); // NEV
|
||||
- All timestamps in logs and error messages
|
||||
- All date parameters in queries
|
||||
|
||||
### 4. No Commits Without Permission
|
||||
**NEVER** commit changes to git automatically. Always wait for explicit user instruction to commit.
|
||||
### 4. Git Operations - NEVER Without Explicit Permission
|
||||
**CRITICAL**: NEVER execute `git commit` or `git push` commands automatically. ALWAYS wait for explicit user instruction.
|
||||
|
||||
**Rules**:
|
||||
- Only commit when user explicitly says "commit" or "commit this"
|
||||
- Only push when user explicitly says "push" or "push to remote"
|
||||
- Stage files with `git add` ONLY when about to commit per user request
|
||||
|
||||
### 5. MediatR Command/Query File Organization
|
||||
**IMPORTANT**: Commands/Queries and their Handlers must be in the SAME file.
|
||||
|
||||
**Example**:
|
||||
```csharp
|
||||
// ✅ CORRECT - CreateEmailProfileCommand.cs contains BOTH
|
||||
public record CreateEmailProfileCommand : IRequest<int> { ... }
|
||||
|
||||
public class CreateEmailProfileCommandHandler : IRequestHandler<CreateEmailProfileCommand, int> { ... }
|
||||
|
||||
// ❌ WRONG - Separate files
|
||||
// CreateEmailProfileCommand.cs (command only)
|
||||
// CreateEmailProfileCommandHandler.cs (handler only)
|
||||
```
|
||||
|
||||
**File Naming**:
|
||||
- Commands: `{Verb}{Entity}Command.cs` (e.g., `CreateEmailProfileCommand.cs`)
|
||||
- Queries: `{Verb}{Entity}Query.cs` (e.g., `GetEmailProfilesQuery.cs`)
|
||||
|
||||
---
|
||||
|
||||
@@ -25,6 +25,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
STATUS.md = STATUS.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EmailProfiler.Common", "legacy\App\EmailProfiler.Common\EmailProfiler.Common.vbproj", "{9F748DCD-952E-40A0-9DAD-65BF8A39B231}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "legacy", "legacy", "{EAFC1552-2C62-4C00-AE27-47D76FEAE9F5}"
|
||||
EndProject
|
||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EmailProfiler.Service", "legacy\App\EmailProfiler.Service\EmailProfiler.Service.vbproj", "{1F3C569B-91DA-427F-8D81-BBCC556B11A4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -51,6 +57,14 @@ Global
|
||||
{211FB65F-2406-474E-A426-DA246B250AB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{211FB65F-2406-474E-A426-DA246B250AB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{211FB65F-2406-474E-A426-DA246B250AB8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9F748DCD-952E-40A0-9DAD-65BF8A39B231}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9F748DCD-952E-40A0-9DAD-65BF8A39B231}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9F748DCD-952E-40A0-9DAD-65BF8A39B231}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9F748DCD-952E-40A0-9DAD-65BF8A39B231}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1F3C569B-91DA-427F-8D81-BBCC556B11A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1F3C569B-91DA-427F-8D81-BBCC556B11A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1F3C569B-91DA-427F-8D81-BBCC556B11A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1F3C569B-91DA-427F-8D81-BBCC556B11A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -61,6 +75,8 @@ Global
|
||||
{76ADC1D0-4DFA-0B1E-57C9-2636434A0043} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{1874A827-C6A5-EB5E-0FE9-30A7200382B7} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{211FB65F-2406-474E-A426-DA246B250AB8} = {4F20FEFD-9289-42C6-ABA6-8DB236D74559}
|
||||
{9F748DCD-952E-40A0-9DAD-65BF8A39B231} = {EAFC1552-2C62-4C00-AE27-47D76FEAE9F5}
|
||||
{1F3C569B-91DA-427F-8D81-BBCC556B11A4} = {EAFC1552-2C62-4C00-AE27-47D76FEAE9F5}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {90E29FDC-F6C6-414F-94BF-25DF61D18060}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailAccounts.Commands;
|
||||
@@ -22,3 +24,35 @@ public record CreateEmailAccountCommand : IRequest<int>
|
||||
public string? EncryptedClientSecret { get; init; } // Already encrypted by client
|
||||
public bool IsActive { get; init; } = true;
|
||||
}
|
||||
|
||||
public class CreateEmailAccountCommandHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<CreateEmailAccountCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(CreateEmailAccountCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var account = new EmailAccount
|
||||
{
|
||||
AccountName = request.AccountName,
|
||||
Username = request.Username,
|
||||
ImapServer = request.ImapServer,
|
||||
ImapPort = request.ImapPort,
|
||||
ImapUseSsl = request.ImapUseSsl,
|
||||
SmtpServer = request.SmtpServer,
|
||||
SmtpPort = request.SmtpPort,
|
||||
SmtpUseSsl = request.SmtpUseSsl,
|
||||
UseOAuth2 = request.UseOAuth2,
|
||||
EncryptedPassword = request.EncryptedPassword,
|
||||
TenantId = request.TenantId,
|
||||
ClientId = request.ClientId,
|
||||
EncryptedClientSecret = request.EncryptedClientSecret,
|
||||
IsActive = request.IsActive,
|
||||
AddedWhen = DateTime.Now,
|
||||
AddedWho = "System" // TODO: Get from current user context
|
||||
};
|
||||
|
||||
var createdAccount = await unitOfWork.EmailAccounts.AddAsync(account, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return createdAccount.Id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailAccounts.Commands;
|
||||
|
||||
public class CreateEmailAccountCommandHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<CreateEmailAccountCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(CreateEmailAccountCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var account = new EmailAccount
|
||||
{
|
||||
AccountName = request.AccountName,
|
||||
Username = request.Username,
|
||||
ImapServer = request.ImapServer,
|
||||
ImapPort = request.ImapPort,
|
||||
ImapUseSsl = request.ImapUseSsl,
|
||||
SmtpServer = request.SmtpServer,
|
||||
SmtpPort = request.SmtpPort,
|
||||
SmtpUseSsl = request.SmtpUseSsl,
|
||||
UseOAuth2 = request.UseOAuth2,
|
||||
EncryptedPassword = request.EncryptedPassword,
|
||||
TenantId = request.TenantId,
|
||||
ClientId = request.ClientId,
|
||||
EncryptedClientSecret = request.EncryptedClientSecret,
|
||||
IsActive = request.IsActive,
|
||||
AddedWhen = DateTime.Now,
|
||||
AddedWho = "System" // TODO: Get from current user context
|
||||
};
|
||||
|
||||
var createdAccount = await unitOfWork.EmailAccounts.AddAsync(account, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return createdAccount.Id;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Services;
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
using DigitalData.EmailProfiler.Domain.Enums;
|
||||
using DigitalData.EmailProfiler.Domain.Events;
|
||||
using DigitalData.EmailProfiler.Domain.Exceptions;
|
||||
using DigitalData.EmailProfiler.Domain.Services;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailProcessing.Commands;
|
||||
@@ -26,3 +33,120 @@ public record AttachmentData(
|
||||
byte[] Content,
|
||||
string ContentType,
|
||||
long SizeBytes);
|
||||
|
||||
public class ProcessEmailCommandHandler(
|
||||
IUnitOfWork unitOfWork,
|
||||
IPublisher publisher,
|
||||
MessageIdGenerator messageIdGenerator,
|
||||
IPdfProcessingService pdfService,
|
||||
IDmsService dmsService)
|
||||
: IRequestHandler<ProcessEmailCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(ProcessEmailCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. Get profile with related entities
|
||||
var profile = await unitOfWork.EmailProfiles.GetWithRelatedEntitiesAsync(request.ProfileId, cancellationToken)
|
||||
?? throw new DomainException($"Profile with ID {request.ProfileId} not found");
|
||||
|
||||
// 2. Generate message ID hash for duplicate detection
|
||||
var messageId = messageIdGenerator.Generate(
|
||||
request.MessageId,
|
||||
request.Sender,
|
||||
request.ReceivedDate,
|
||||
request.Subject);
|
||||
|
||||
// 3. Check for duplicates
|
||||
var isDuplicate = await unitOfWork.EmailHistories.IsDuplicateAsync(messageId.Hash, cancellationToken);
|
||||
if (isDuplicate)
|
||||
{
|
||||
throw new ValidationException("Email already processed (duplicate detected)", ErrorCode.DuplicateMessageId);
|
||||
}
|
||||
|
||||
// 4. Create email history record
|
||||
var emailHistory = new EmailHistory
|
||||
{
|
||||
ProfileId = profile.Id,
|
||||
MessageIdHash = messageId.Hash,
|
||||
OriginalMessageId = request.MessageId,
|
||||
SenderAddress = request.Sender,
|
||||
EmailDate = request.ReceivedDate,
|
||||
Subject = request.Subject,
|
||||
EmailBodyText = request.BodyText,
|
||||
EmailBodyHtml = request.BodyHtml,
|
||||
Status = EmailStatus.Processing.ToString(),
|
||||
AddedWhen = DateTime.Now
|
||||
};
|
||||
|
||||
var createdHistory = await unitOfWork.EmailHistories.AddAsync(emailHistory, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
// 5. Process attachments
|
||||
foreach (var attachmentData in request.Attachments)
|
||||
{
|
||||
var attachment = new EmailAttachment
|
||||
{
|
||||
EmailHistoryId = createdHistory.Id,
|
||||
OriginalFileName = attachmentData.FileName,
|
||||
SavedFileName = attachmentData.FileName, // TODO: Generate unique name
|
||||
FilePath = string.Empty, // TODO: Save to disk and get path
|
||||
FileSize = attachmentData.SizeBytes,
|
||||
Extension = Path.GetExtension(attachmentData.FileName),
|
||||
Status = AttachmentStatus.Pending.ToString(),
|
||||
AddedWhen = DateTime.Now
|
||||
};
|
||||
|
||||
// Validate PDF attachments
|
||||
if (attachmentData.ContentType.Contains("pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
using var stream = new MemoryStream(attachmentData.Content);
|
||||
var isValidPdf = await pdfService.IsValidPdfAsync(stream, cancellationToken);
|
||||
|
||||
if (isValidPdf)
|
||||
{
|
||||
attachment.MarkAsValid();
|
||||
}
|
||||
else
|
||||
{
|
||||
attachment.MarkAsCorrupt(ErrorCode.PdfStructureInvalid, "Invalid PDF structure");
|
||||
}
|
||||
}
|
||||
|
||||
createdHistory.Attachments.Add(attachment);
|
||||
}
|
||||
|
||||
// 6. Archive to DMS if configured
|
||||
if (profile.EmailProcess != null && profile.EmailProcess.EnableWindreamImport)
|
||||
{
|
||||
// TODO: Implement DMS archiving with indexing steps
|
||||
// This will be implemented based on ProcessSteps and IndexingSteps
|
||||
}
|
||||
|
||||
// 7. Mark as processed
|
||||
createdHistory.MarkAsProcessed();
|
||||
await unitOfWork.EmailHistories.UpdateAsync(createdHistory, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 8. Publish domain event
|
||||
await publisher.Publish(
|
||||
new EmailProcessedEvent(
|
||||
createdHistory.Id,
|
||||
profile.Id,
|
||||
messageId.Hash,
|
||||
EmailStatus.Processed),
|
||||
cancellationToken);
|
||||
|
||||
return createdHistory.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Mark as failed
|
||||
createdHistory.MarkAsFailed(ErrorCode.AttachmentExtractionFailed, ex.Message);
|
||||
await unitOfWork.EmailHistories.UpdateAsync(createdHistory, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Services;
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
using DigitalData.EmailProfiler.Domain.Enums;
|
||||
using DigitalData.EmailProfiler.Domain.Events;
|
||||
using DigitalData.EmailProfiler.Domain.Exceptions;
|
||||
using DigitalData.EmailProfiler.Domain.Services;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailProcessing.Commands;
|
||||
|
||||
public class ProcessEmailCommandHandler(
|
||||
IUnitOfWork unitOfWork,
|
||||
IPublisher publisher,
|
||||
MessageIdGenerator messageIdGenerator,
|
||||
IPdfProcessingService pdfService,
|
||||
IDmsService dmsService)
|
||||
: IRequestHandler<ProcessEmailCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(ProcessEmailCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. Get profile with related entities
|
||||
var profile = await unitOfWork.EmailProfiles.GetWithRelatedEntitiesAsync(request.ProfileId, cancellationToken)
|
||||
?? throw new DomainException($"Profile with ID {request.ProfileId} not found");
|
||||
|
||||
// 2. Generate message ID hash for duplicate detection
|
||||
var messageId = messageIdGenerator.Generate(
|
||||
request.MessageId,
|
||||
request.Sender,
|
||||
request.ReceivedDate,
|
||||
request.Subject);
|
||||
|
||||
// 3. Check for duplicates
|
||||
var isDuplicate = await unitOfWork.EmailHistories.IsDuplicateAsync(messageId.Hash, cancellationToken);
|
||||
if (isDuplicate)
|
||||
{
|
||||
throw new ValidationException("Email already processed (duplicate detected)", ErrorCode.DuplicateMessageId);
|
||||
}
|
||||
|
||||
// 4. Create email history record
|
||||
var emailHistory = new EmailHistory
|
||||
{
|
||||
ProfileId = profile.Id,
|
||||
MessageIdHash = messageId.Hash,
|
||||
OriginalMessageId = request.MessageId,
|
||||
SenderAddress = request.Sender,
|
||||
EmailDate = request.ReceivedDate,
|
||||
Subject = request.Subject,
|
||||
EmailBodyText = request.BodyText,
|
||||
EmailBodyHtml = request.BodyHtml,
|
||||
Status = EmailStatus.Processing.ToString(),
|
||||
AddedWhen = DateTime.Now
|
||||
};
|
||||
|
||||
var createdHistory = await unitOfWork.EmailHistories.AddAsync(emailHistory, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
// 5. Process attachments
|
||||
foreach (var attachmentData in request.Attachments)
|
||||
{
|
||||
var attachment = new EmailAttachment
|
||||
{
|
||||
EmailHistoryId = createdHistory.Id,
|
||||
OriginalFileName = attachmentData.FileName,
|
||||
SavedFileName = attachmentData.FileName, // TODO: Generate unique name
|
||||
FilePath = string.Empty, // TODO: Save to disk and get path
|
||||
FileSize = attachmentData.SizeBytes,
|
||||
Extension = Path.GetExtension(attachmentData.FileName),
|
||||
Status = AttachmentStatus.Pending.ToString(),
|
||||
AddedWhen = DateTime.Now
|
||||
};
|
||||
|
||||
// Validate PDF attachments
|
||||
if (attachmentData.ContentType.Contains("pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
using var stream = new MemoryStream(attachmentData.Content);
|
||||
var isValidPdf = await pdfService.IsValidPdfAsync(stream, cancellationToken);
|
||||
|
||||
if (isValidPdf)
|
||||
{
|
||||
attachment.MarkAsValid();
|
||||
}
|
||||
else
|
||||
{
|
||||
attachment.MarkAsCorrupt(ErrorCode.PdfStructureInvalid, "Invalid PDF structure");
|
||||
}
|
||||
}
|
||||
|
||||
createdHistory.Attachments.Add(attachment);
|
||||
}
|
||||
|
||||
// 6. Archive to DMS if configured
|
||||
if (profile.EmailProcess != null && profile.EmailProcess.EnableWindreamImport)
|
||||
{
|
||||
// TODO: Implement DMS archiving with indexing steps
|
||||
// This will be implemented based on ProcessSteps and IndexingSteps
|
||||
}
|
||||
|
||||
// 7. Mark as processed
|
||||
createdHistory.MarkAsProcessed();
|
||||
await unitOfWork.EmailHistories.UpdateAsync(createdHistory, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 8. Publish domain event
|
||||
await publisher.Publish(
|
||||
new EmailProcessedEvent(
|
||||
createdHistory.Id,
|
||||
profile.Id,
|
||||
messageId.Hash,
|
||||
EmailStatus.Processed),
|
||||
cancellationToken);
|
||||
|
||||
return createdHistory.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Mark as failed
|
||||
createdHistory.MarkAsFailed(ErrorCode.AttachmentExtractionFailed, ex.Message);
|
||||
await unitOfWork.EmailHistories.UpdateAsync(createdHistory, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailProfiles.Commands;
|
||||
@@ -14,3 +16,27 @@ public record CreateEmailProfileCommand : IRequest<int>
|
||||
public int PollIntervalMinutes { get; init; } = 15;
|
||||
public bool IsActive { get; init; } = true;
|
||||
}
|
||||
|
||||
public class CreateEmailProfileCommandHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<CreateEmailProfileCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(CreateEmailProfileCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = new EmailProfile
|
||||
{
|
||||
ProfileName = request.ProfileName,
|
||||
EmailAccountId = request.EmailAccountId,
|
||||
ProcessId = request.ProcessId,
|
||||
ValidationSql = request.ValidationSql,
|
||||
PollIntervalMinutes = request.PollIntervalMinutes,
|
||||
IsActive = request.IsActive,
|
||||
AddedWhen = DateTime.Now,
|
||||
AddedWho = "System" // TODO: Get from current user context
|
||||
};
|
||||
|
||||
var createdProfile = await unitOfWork.EmailProfiles.AddAsync(profile, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return createdProfile.Id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailProfiles.Commands;
|
||||
|
||||
public class CreateEmailProfileCommandHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<CreateEmailProfileCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(CreateEmailProfileCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = new EmailProfile
|
||||
{
|
||||
ProfileName = request.ProfileName,
|
||||
EmailAccountId = request.EmailAccountId,
|
||||
ProcessId = request.ProcessId,
|
||||
ValidationSql = request.ValidationSql,
|
||||
PollIntervalMinutes = request.PollIntervalMinutes,
|
||||
IsActive = request.IsActive,
|
||||
AddedWhen = DateTime.Now,
|
||||
AddedWho = "System" // TODO: Get from current user context
|
||||
};
|
||||
|
||||
var createdProfile = await unitOfWork.EmailProfiles.AddAsync(profile, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return createdProfile.Id;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Domain.Exceptions;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailProfiles.Commands;
|
||||
@@ -6,3 +8,18 @@ namespace DigitalData.EmailProfiler.Application.Features.EmailProfiles.Commands;
|
||||
/// Command to delete an email profile.
|
||||
/// </summary>
|
||||
public record DeleteEmailProfileCommand(int Id) : IRequest<Unit>;
|
||||
|
||||
public class DeleteEmailProfileCommandHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<DeleteEmailProfileCommand, Unit>
|
||||
{
|
||||
public async Task<Unit> Handle(DeleteEmailProfileCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await unitOfWork.EmailProfiles.GetByIdAsync(request.Id, cancellationToken)
|
||||
?? throw new DomainException($"Email profile with ID {request.Id} not found");
|
||||
|
||||
await unitOfWork.EmailProfiles.DeleteAsync(profile, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Domain.Exceptions;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailProfiles.Commands;
|
||||
|
||||
public class DeleteEmailProfileCommandHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<DeleteEmailProfileCommand, Unit>
|
||||
{
|
||||
public async Task<Unit> Handle(DeleteEmailProfileCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await unitOfWork.EmailProfiles.GetByIdAsync(request.Id, cancellationToken)
|
||||
?? throw new DomainException($"Email profile with ID {request.Id} not found");
|
||||
|
||||
await unitOfWork.EmailProfiles.DeleteAsync(profile, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Domain.Exceptions;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailProfiles.Commands;
|
||||
@@ -13,3 +15,25 @@ public record UpdateEmailProfileCommand : IRequest<Unit>
|
||||
public int PollIntervalMinutes { get; init; }
|
||||
public bool IsActive { get; init; }
|
||||
}
|
||||
|
||||
public class UpdateEmailProfileCommandHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<UpdateEmailProfileCommand, Unit>
|
||||
{
|
||||
public async Task<Unit> Handle(UpdateEmailProfileCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await unitOfWork.EmailProfiles.GetByIdAsync(request.Id, cancellationToken)
|
||||
?? throw new DomainException($"Email profile with ID {request.Id} not found");
|
||||
|
||||
profile.ProfileName = request.ProfileName;
|
||||
profile.ValidationSql = request.ValidationSql;
|
||||
profile.PollIntervalMinutes = request.PollIntervalMinutes;
|
||||
profile.IsActive = request.IsActive;
|
||||
profile.ChangedWhen = DateTime.Now;
|
||||
profile.ChangedWho = "System"; // TODO: Get from current user context
|
||||
|
||||
await unitOfWork.EmailProfiles.UpdateAsync(profile, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
using DigitalData.EmailProfiler.Application.Interfaces.Repositories;
|
||||
using DigitalData.EmailProfiler.Domain.Exceptions;
|
||||
using MediatR;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Features.EmailProfiles.Commands;
|
||||
|
||||
public class UpdateEmailProfileCommandHandler(IUnitOfWork unitOfWork)
|
||||
: IRequestHandler<UpdateEmailProfileCommand, Unit>
|
||||
{
|
||||
public async Task<Unit> Handle(UpdateEmailProfileCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await unitOfWork.EmailProfiles.GetByIdAsync(request.Id, cancellationToken)
|
||||
?? throw new DomainException($"Email profile with ID {request.Id} not found");
|
||||
|
||||
profile.ProfileName = request.ProfileName;
|
||||
profile.ValidationSql = request.ValidationSql;
|
||||
profile.PollIntervalMinutes = request.PollIntervalMinutes;
|
||||
profile.IsActive = request.IsActive;
|
||||
profile.ChangedWhen = DateTime.Now;
|
||||
profile.ChangedWho = "System"; // TODO: Get from current user context
|
||||
|
||||
await unitOfWork.EmailProfiles.UpdateAsync(profile, cancellationToken);
|
||||
await unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user