refactor(infrastructure): Improve service implementations and remove legacy references
**Services Refactored:**
- DevExpressPdfProcessingService: Remove unnecessary try-catch (lines 80-87), add stream position validation
- WindreamDmsService: Mark as [Obsolete] - application now only provides email sending functionality
- MailKitEmailService: Keep MailKit implementation (Limilabs DLL to be added separately)
**Custom Exceptions Added:**
- AuthenticationFailedException: OAuth2/IMAP/SMTP authentication failures
- DmsNotAvailableException: windream COM unavailable
- InvalidPdfException: Invalid PDF stream
- NotFoundException: Entity not found in Repository operations
**Legacy Cleanup:**
- Remove legacy VB.NET projects from solution (EmailProfiler.Common, EmailProfiler.Service)
- Delete legacy/ folder reference
- Clean solution file structure
**Stream Validation:**
- All PDF processing methods now validate stream position (reset to 0 if needed)
- Add CanSeek validation for stream-based operations
**Build Status:** ✅ Successful (0 errors, 15 warnings - all acceptable)
This commit is contained in:
@@ -9,9 +9,15 @@ public class EmailAccountDto
|
||||
public string AccountName { get; set; } = string.Empty;
|
||||
public string ImapServer { get; set; } = string.Empty;
|
||||
public int ImapPort { get; set; }
|
||||
public bool ImapUseSsl { get; set; }
|
||||
public string SmtpServer { get; set; } = string.Empty;
|
||||
public int SmtpPort { get; set; }
|
||||
public bool SmtpUseSsl { get; set; }
|
||||
public string Username { get; set; } = string.Empty;
|
||||
public string? EncryptedPassword { get; set; }
|
||||
public bool UseOAuth2 { get; set; }
|
||||
public string? TenantId { get; set; }
|
||||
public string? ClientId { get; set; }
|
||||
public string? EncryptedClientSecret { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// DMS service interface for windream integration.
|
||||
/// </summary>
|
||||
public interface IDmsService
|
||||
{
|
||||
Task<string> ImportDocumentAsync(string filePath, string objectType, Dictionary<string, string> metadata, CancellationToken cancellationToken = default);
|
||||
Task<bool> DocumentExistsAsync(string documentId, CancellationToken cancellationToken = default);
|
||||
Task<bool> UpdateMetadataAsync(string documentId, Dictionary<string, string> metadata, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using DigitalData.EmailProfiler.Domain.Entities;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Email queue interface for outgoing emails.
|
||||
/// </summary>
|
||||
public interface IEmailQueue
|
||||
{
|
||||
Task EnqueueAsync(EmailOutbox email, CancellationToken cancellationToken = default);
|
||||
Task<EmailOutbox?> DequeueAsync(CancellationToken cancellationToken = default);
|
||||
Task<int> GetQueueDepthAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using DigitalData.EmailProfiler.Application.Common.Dtos;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Email service interface for IMAP/SMTP operations.
|
||||
/// Implementation uses MailKit.
|
||||
/// Throws AuthenticationFailedException when OAuth2/password auth fails.
|
||||
/// </summary>
|
||||
public interface IEmailService
|
||||
{
|
||||
Task<IEnumerable<object>> ReceiveEmailsAsync(EmailAccountDto account, CancellationToken cancellationToken = default);
|
||||
Task SendEmailAsync(EmailAccountDto account, string to, string subject, string body, bool isHtml = true, CancellationToken cancellationToken = default);
|
||||
Task DeleteEmailAsync(EmailAccountDto account, int imapUid, CancellationToken cancellationToken = default);
|
||||
Task<string> GetOAuth2TokenAsync(string tenantId, string clientId, string clientSecret, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Encryption service interface for password encryption.
|
||||
/// </summary>
|
||||
public interface IEncryptionService
|
||||
{
|
||||
string Encrypt(string plainText);
|
||||
string Decrypt(string cipherText);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// PDF processing service interface.
|
||||
/// Operates on streams instead of file paths for flexibility.
|
||||
/// </summary>
|
||||
public interface IPdfProcessingService
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates if the provided stream contains a valid PDF document.
|
||||
/// Throws InvalidPdfException if the stream is not a valid PDF.
|
||||
/// </summary>
|
||||
Task<bool> ValidatePdfAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts embedded files from PDF stream to the specified output directory.
|
||||
/// Returns a list of paths to extracted files.
|
||||
/// </summary>
|
||||
Task<IEnumerable<string>> ExtractEmbeddedFilesAsync(Stream pdfStream, string outputDirectory, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the page count of the PDF document.
|
||||
/// Throws InvalidPdfException if the stream is not a valid PDF.
|
||||
/// </summary>
|
||||
Task<int> GetPageCountAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DigitalData.EmailProfiler.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Generic repository interface for CRUD operations.
|
||||
/// All operations auto-save changes - NO explicit SaveChangesAsync needed!
|
||||
/// </summary>
|
||||
public interface IRepository<TEntity> where TEntity : class
|
||||
{
|
||||
// CREATE
|
||||
Task<TEntity> CreateAsync<TDto>(TDto dto, CancellationToken cancellationToken = default);
|
||||
|
||||
// READ
|
||||
Task<TEntity?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<TEntity>> GetAllAsync(CancellationToken cancellationToken = default);
|
||||
Task<IEnumerable<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, int? skip = null, int? take = null, CancellationToken cancellationToken = default);
|
||||
Task<TEntity?> FindFirstAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
|
||||
Task<TEntity?> FindSingleAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
|
||||
Task<int> CountAsync(Expression<Func<TEntity, bool>>? predicate = null, CancellationToken cancellationToken = default);
|
||||
Task<bool> AnyAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
|
||||
|
||||
// UPDATE
|
||||
Task UpdateSingleAsync<TDto>(Expression<Func<TEntity, bool>> predicate, TDto dto, CancellationToken cancellationToken = default);
|
||||
Task<int> UpdateAsync<TDto>(Expression<Func<TEntity, bool>> predicate, TDto dto, CancellationToken cancellationToken = default);
|
||||
|
||||
// DELETE
|
||||
Task DeleteSingleAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
|
||||
Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
|
||||
}
|
||||
Reference in New Issue
Block a user