using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; using Cleanuparr.Domain.Enums; using Cleanuparr.Persistence.Models.State; using Microsoft.EntityFrameworkCore; namespace Cleanuparr.Persistence.Models.Events; /// /// Represents an event in the system /// [Index(nameof(Timestamp), IsDescending = [true])] [Index(nameof(EventType))] [Index(nameof(Severity))] [Index(nameof(JobRunId))] [Index(nameof(ArrInstanceId))] [Index(nameof(CycleId))] [Index(nameof(DeleteReason))] public class AppEvent { [Key] public Guid Id { get; set; } = Guid.CreateVersion7(); public DateTimeOffset Timestamp { get; set; } = DateTimeOffset.UtcNow; [Required] public EventType EventType { get; set; } [Required] [MaxLength(1000)] public string Message { get; set; } = string.Empty; [Required] public required EventSeverity Severity { get; set; } /// /// Optional correlation ID to link related events /// public Guid? TrackingId { get; set; } public Guid? StrikeId { get; set; } [JsonIgnore] public Strike? Strike { get; set; } public Guid? JobRunId { get; set; } [JsonIgnore] public JobRun? JobRun { get; set; } /// /// The ID of the arr instance that generated this event /// public Guid? ArrInstanceId { get; set; } /// /// The ID of the download client involved in this event /// public Guid? DownloadClientId { get; set; } /// /// Status of the search command (only set for SearchTriggered events) /// public SearchCommandStatus? SearchStatus { get; set; } /// /// When the search command completed (only set for SearchTriggered events) /// public DateTimeOffset? CompletedAt { get; set; } /// /// The Seeker cycle ID associated with this event (only set for SearchTriggered events) /// public Guid? CycleId { get; set; } public bool IsDryRun { get; set; } // Item context (most events) /// /// Title of the download item this event refers to /// [MaxLength(500)] public string? ItemTitle { get; set; } /// /// Hash / download ID of the item this event refers to /// [MaxLength(100)] public string? ItemHash { get; set; } /// /// Strike number at the time of the event (strike / reset events) /// public int? StrikeCount { get; set; } /// /// Import failure reasons (FailedImportStrike events) /// public List FailedImportReasons { get; set; } = []; /// /// Reason a queue item was deleted (QueueItemDeleted events) /// public DeleteReason? DeleteReason { get; set; } /// /// Whether the item was also removed from the download client (QueueItemDeleted events) /// public bool? RemoveFromClient { get; set; } /// /// Reason a download was cleaned (DownloadCleaned events) /// public CleanReason? CleanReason { get; set; } /// /// Category of the cleaned download (DownloadCleaned events) /// [MaxLength(200)] public string? CleanedCategory { get; set; } /// /// Seed ratio at the time of cleaning (DownloadCleaned events) /// public double? SeedRatio { get; set; } /// /// Seeding time in hours at the time of cleaning (DownloadCleaned events) /// public double? SeedingTimeHours { get; set; } /// /// Previous category (CategoryChanged events) /// [MaxLength(200)] public string? OldCategory { get; set; } /// /// New category or tag (CategoryChanged events) /// [MaxLength(200)] public string? NewCategory { get; set; } /// /// Whether the category change was a tag rather than a category (CategoryChanged events) /// public bool? IsCategoryTag { get; set; } /// /// Type of search (SearchTriggered events) /// public SeekerSearchType? SearchType { get; set; } /// /// Reason a search was triggered (SearchTriggered events) /// public SeekerSearchReason? SearchReason { get; set; } /// /// What the searched Sonarr unit holds (SearchTriggered events) /// public SeekerContentKind? ContentKind { get; set; } /// /// Titles of items grabbed after search completion, populated by SeekerCommandMonitor (SearchTriggered events) /// public List GrabbedItems { get; set; } = []; // Used only for notifications [NotMapped] public InstanceType? InstanceType { get; set; } [NotMapped] public string? InstanceUrl { get; set; } [NotMapped] public DownloadClientTypeName? DownloadClientType { get; set; } [NotMapped] public string? DownloadClientName { get; set; } }