using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using ValidationException = Cleanuparr.Domain.Exceptions.ValidationException; namespace Cleanuparr.Persistence.Models.Configuration.DownloadCleaner; public sealed record UnlinkedConfig : IConfig { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; } = Guid.NewGuid(); public Guid DownloadClientConfigId { get; set; } public DownloadClientConfig DownloadClientConfig { get; set; } = null!; public bool Enabled { get; set; } = false; public string TargetCategory { get; set; } = "cleanuparr-unlinked"; public bool UseTag { get; set; } public List IgnoredRootDirs { get; set; } = []; public List Categories { get; set; } = []; /// /// The path prefix reported by the download client (e.g., "/downloads"). /// When set, this prefix is replaced with when resolving file paths. /// public string? DownloadDirectorySource { get; set; } /// /// The actual local mount path (e.g., "/downloads-other"). /// Replaces in file paths for hardlink checking. /// public string? DownloadDirectoryTarget { get; set; } public void Validate() { if (!Enabled) { return; } if (string.IsNullOrWhiteSpace(TargetCategory)) { throw new ValidationException("Unlinked target category is required"); } if (Categories.Count is 0) { throw new ValidationException("No unlinked categories configured"); } if (Categories.Contains(TargetCategory, StringComparer.OrdinalIgnoreCase)) { throw new ValidationException("The unlinked target category should not be present in unlinked categories"); } if (Categories.Any(string.IsNullOrWhiteSpace)) { throw new ValidationException("Empty unlinked category filter found"); } if (!string.IsNullOrEmpty(DownloadDirectorySource) != !string.IsNullOrEmpty(DownloadDirectoryTarget)) { throw new ValidationException("Both download directory source and target must be set, or both must be empty"); } foreach (var dir in IgnoredRootDirs.Where(d => !string.IsNullOrEmpty(d))) { if (!Directory.Exists(dir)) { throw new ValidationException($"{dir} root directory does not exist or is not accessible (check permissions)"); } } } }