| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- using System.IO.Abstractions;
- namespace qdr.app.studiou.orders2printpack.EmailStorage
- {
- /// <summary>
- /// Helper class for working with email items and their file operations.
- /// Provides a convenient wrapper around MetadataItem with additional functionality
- /// for file system operations, validation, and state management.
- /// </summary>
- public class EmailItem
- {
- #region Private Fields
-
- /// <summary>
- /// The underlying metadata item containing email and processing information
- /// </summary>
- private readonly MetadataItem _metadata;
-
- /// <summary>
- /// Base directory path where email item directories are located
- /// </summary>
- private readonly string _basePath;
- /// <summary>
- /// File system abstraction for testable file operations
- /// </summary>
- private readonly IFileSystem _fileSystem;
- #endregion
- #region Constructor
- /// <summary>
- /// Initializes a new instance of the EmailItem class
- /// </summary>
- /// <param name="metadata">The metadata item containing email information</param>
- /// <param name="basePath">Base directory path for file operations</param>
- /// <param name="fileSystem">File system abstraction for file operations</param>
- /// <exception cref="ArgumentNullException">Thrown when metadata, basePath, or fileSystem is null</exception>
- public EmailItem(MetadataItem metadata, string basePath, IFileSystem fileSystem)
- {
- _metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
- _basePath = basePath ?? throw new ArgumentNullException(nameof(basePath));
- _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
- }
- #endregion
- #region Public Properties
- /// <summary>
- /// Gets the underlying metadata item
- /// </summary>
- public MetadataItem Metadata => _metadata;
-
- /// <summary>
- /// Gets the full directory path for this email item
- /// Combines the base path with the directory name from metadata
- /// </summary>
- public string DirectoryPath => _fileSystem.Path.Combine(_basePath, _metadata.DirectoryName);
-
- /// <summary>
- /// Gets a value indicating whether the directory exists on the file system
- /// </summary>
- public bool DirectoryExists => _fileSystem.Directory.Exists(DirectoryPath);
-
- /// <summary>
- /// Gets all JPG files in the email item's directory
- /// Returns an empty enumerable if the directory doesn't exist
- /// </summary>
- public IEnumerable<string> JpgFiles =>
- DirectoryExists ? _fileSystem.Directory.GetFiles(DirectoryPath, "*.jpg") : Enumerable.Empty<string>();
-
- /// <summary>
- /// Gets the count of JPG files in the directory
- /// </summary>
- public int FileCount => JpgFiles.Count();
-
- /// <summary>
- /// Gets the total size in bytes of all JPG files in the directory
- /// </summary>
- public long TotalFileSize => JpgFiles.Sum(f => _fileSystem.FileInfo.New(f).Length);
-
- /// <summary>
- /// Gets a value indicating whether this item is ready for processing
- /// Checks that the state is Ready, directory exists, and contains files
- /// </summary>
- public bool IsReadyForProcessing =>
- _metadata.State == EmailStateEnum.Ready && DirectoryExists && FileCount > 0;
-
- /// <summary>
- /// Gets a value indicating whether this item can be reset
- /// Items cannot be reset while they are being processed or uploaded
- /// </summary>
- public bool CanBeReset =>
- _metadata.State != EmailStateEnum.Processing &&
- _metadata.State != EmailStateEnum.Uploading;
- /// <summary>
- /// Gets the normalized filename for the recipient (safe for file system)
- /// Replaces @ with _at_ and . with _dot_ to create filesystem-safe names
- /// </summary>
- public string NormalizedRecipient =>
- _metadata.EmailAddress.Replace("@", "_at_").Replace(".", "_dot_");
- #endregion
- #region Public Methods
- /// <summary>
- /// Generates the zip filename for this item based on recipient and timestamp
- /// </summary>
- /// <param name="timestamp">Optional timestamp to use, defaults to current time</param>
- /// <returns>A formatted zip filename in the format: studioufoto_{recipient}_{timestamp}.zip</returns>
- public string GenerateZipFileName(DateTime? timestamp = null) =>
- $"studioufoto_{NormalizedRecipient}_{(timestamp ?? DateTime.Now):yyyyMMdd_HHmmss}.zip";
- /// <summary>
- /// Validates that the item is in a consistent state for processing
- /// </summary>
- /// <returns>A tuple containing validation result and list of issues found</returns>
- public (bool IsValid, List<string> Issues) Validate()
- {
- var issues = new List<string>();
- // Check required email address
- if (string.IsNullOrEmpty(_metadata.EmailAddress))
- issues.Add("Email address is required");
- // Check directory and files existence
- if (!DirectoryExists)
- issues.Add($"Directory does not exist: {DirectoryPath}");
- else if (FileCount == 0)
- issues.Add("No JPG files found in directory");
- // Check required email content
- if (string.IsNullOrEmpty(_metadata.Subject))
- issues.Add("Email subject is required");
- if (string.IsNullOrEmpty(_metadata.Body))
- issues.Add("Email body is required");
- return (issues.Count == 0, issues);
- }
- /// <summary>
- /// Gets a summary of the item for display purposes
- /// Includes recipient, file count, current state, and associated orders
- /// </summary>
- /// <returns>A formatted summary string</returns>
- public string GetSummary() =>
- $"{_metadata.EmailAddress} - {FileCount} files, {_metadata.State}, Orders: {_metadata.Orders}";
- /// <summary>
- /// Gets detailed file information for all JPG files in the directory
- /// </summary>
- /// <returns>Collection of file information objects</returns>
- public IEnumerable<IFileInfo> GetFileDetails() =>
- JpgFiles.Select(f => _fileSystem.FileInfo.New(f));
- /// <summary>
- /// Checks if a specific file exists in the email item's directory
- /// </summary>
- /// <param name="fileName">Name of the file to check</param>
- /// <returns>True if the file exists, false otherwise</returns>
- public bool FileExists(string fileName)
- {
- if (string.IsNullOrEmpty(fileName))
- return false;
- var filePath = _fileSystem.Path.Combine(DirectoryPath, fileName);
- return _fileSystem.File.Exists(filePath);
- }
- /// <summary>
- /// Gets the full path for a file within the email item's directory
- /// </summary>
- /// <param name="fileName">Name of the file</param>
- /// <returns>Full path to the file</returns>
- public string GetFilePath(string fileName) =>
- _fileSystem.Path.Combine(DirectoryPath, fileName);
- /// <summary>
- /// Creates the email item's directory if it doesn't exist
- /// </summary>
- /// <returns>True if directory was created or already exists, false if creation failed</returns>
- public bool EnsureDirectoryExists()
- {
- try
- {
- if (!DirectoryExists)
- {
- _fileSystem.Directory.CreateDirectory(DirectoryPath);
- }
- return true;
- }
- catch
- {
- return false;
- }
- }
- /// <summary>
- /// Gets file information for a specific file in the directory
- /// </summary>
- /// <param name="fileName">Name of the file</param>
- /// <returns>File information object, or null if file doesn't exist</returns>
- public IFileInfo? GetFileInfo(string fileName)
- {
- if (string.IsNullOrEmpty(fileName))
- return null;
- var filePath = GetFilePath(fileName);
- return _fileSystem.File.Exists(filePath) ? _fileSystem.FileInfo.New(filePath) : null;
- }
- #endregion
- }
- }
|