summaryrefslogtreecommitdiff
path: root/DomainDig/Models.swift
diff options
context:
space:
mode:
Diffstat (limited to 'DomainDig/Models.swift')
-rw-r--r--DomainDig/Models.swift377
1 files changed, 377 insertions, 0 deletions
diff --git a/DomainDig/Models.swift b/DomainDig/Models.swift
index 54bea10..8e1d494 100644
--- a/DomainDig/Models.swift
+++ b/DomainDig/Models.swift
@@ -1336,6 +1336,383 @@ struct MonitoringLog: Codable, Identifiable, Equatable {
}
}
+enum EventSeverity: String, Codable, CaseIterable, Comparable, Identifiable, Sendable {
+ case info
+ case warning
+ case critical
+
+ var id: String { rawValue }
+
+ static func < (lhs: EventSeverity, rhs: EventSeverity) -> Bool {
+ lhs.rank < rhs.rank
+ }
+
+ var title: String {
+ rawValue.capitalized
+ }
+
+ private var rank: Int {
+ switch self {
+ case .info:
+ return 0
+ case .warning:
+ return 1
+ case .critical:
+ return 2
+ }
+ }
+
+ init(monitoringSeverity: MonitoringAlertSeverity) {
+ switch monitoringSeverity {
+ case .info:
+ self = .info
+ case .warning:
+ self = .warning
+ case .critical:
+ self = .critical
+ }
+ }
+}
+
+enum MonitoringEventType: String, Codable, CaseIterable, Identifiable, Sendable {
+ case dnsChanged
+ case certificateUpdated
+ case certificateExpiring
+ case redirectChanged
+ case headersChanged
+ case endpointUnreachable
+ case monitoringFailure
+ case changeDetected
+ case test
+
+ var id: String { rawValue }
+
+ var title: String {
+ switch self {
+ case .dnsChanged:
+ return "DNS Changed"
+ case .certificateUpdated:
+ return "Certificate Updated"
+ case .certificateExpiring:
+ return "Certificate Expiring"
+ case .redirectChanged:
+ return "Redirect Changed"
+ case .headersChanged:
+ return "Headers Changed"
+ case .endpointUnreachable:
+ return "Endpoint Unreachable"
+ case .monitoringFailure:
+ return "Monitoring Failure"
+ case .changeDetected:
+ return "Change Detected"
+ case .test:
+ return "Test Event"
+ }
+ }
+}
+
+struct MonitoringEvent: Codable, Identifiable, Equatable, Sendable {
+ var id: UUID
+ var type: MonitoringEventType
+ var severity: EventSeverity
+ var domain: String
+ var timestamp: Date
+ var summary: String
+ var details: [String: String]
+
+ init(
+ id: UUID = UUID(),
+ type: MonitoringEventType,
+ severity: EventSeverity,
+ domain: String,
+ timestamp: Date = Date(),
+ summary: String,
+ details: [String: String] = [:]
+ ) {
+ self.id = id
+ self.type = type
+ self.severity = severity
+ self.domain = domain
+ self.timestamp = timestamp
+ self.summary = summary
+ self.details = details
+ }
+}
+
+enum IntegrationType: String, Codable, CaseIterable, Identifiable, Sendable {
+ case webhook
+ case slack
+ case email
+
+ var id: String { rawValue }
+
+ var title: String {
+ rawValue.capitalized
+ }
+}
+
+enum SMTPSecurityMode: String, Codable, CaseIterable, Identifiable, Sendable {
+ case plain
+ case directTLS
+
+ var id: String { rawValue }
+
+ var title: String {
+ switch self {
+ case .plain:
+ return "Plain"
+ case .directTLS:
+ return "Direct TLS"
+ }
+ }
+}
+
+struct WebhookIntegrationConfiguration: Codable, Equatable, Sendable {
+ var endpointDisplayHost: String
+ var timeoutSeconds: Double
+ var additionalHeaders: [String: String]
+ var credentialReference: String?
+
+ init(
+ endpointDisplayHost: String = "",
+ timeoutSeconds: Double = 15,
+ additionalHeaders: [String: String] = [:],
+ credentialReference: String? = nil
+ ) {
+ self.endpointDisplayHost = endpointDisplayHost
+ self.timeoutSeconds = timeoutSeconds
+ self.additionalHeaders = additionalHeaders
+ self.credentialReference = credentialReference
+ }
+}
+
+struct SlackIntegrationConfiguration: Codable, Equatable, Sendable {
+ var destinationLabel: String
+ var credentialReference: String?
+
+ init(
+ destinationLabel: String = "Slack",
+ credentialReference: String? = nil
+ ) {
+ self.destinationLabel = destinationLabel
+ self.credentialReference = credentialReference
+ }
+}
+
+struct EmailIntegrationConfiguration: Codable, Equatable, Sendable {
+ var smtpHost: String
+ var port: Int
+ var username: String
+ var senderAddress: String
+ var recipientAddresses: [String]
+ var securityMode: SMTPSecurityMode
+ var credentialReference: String?
+
+ init(
+ smtpHost: String = "",
+ port: Int = 465,
+ username: String = "",
+ senderAddress: String = "",
+ recipientAddresses: [String] = [],
+ securityMode: SMTPSecurityMode = .directTLS,
+ credentialReference: String? = nil
+ ) {
+ self.smtpHost = smtpHost
+ self.port = port
+ self.username = username
+ self.senderAddress = senderAddress
+ self.recipientAddresses = recipientAddresses
+ self.securityMode = securityMode
+ self.credentialReference = credentialReference
+ }
+}
+
+enum IntegrationConfiguration: Codable, Equatable, Sendable {
+ case webhook(WebhookIntegrationConfiguration)
+ case slack(SlackIntegrationConfiguration)
+ case email(EmailIntegrationConfiguration)
+
+ private enum CodingKeys: String, CodingKey {
+ case type
+ case webhook
+ case slack
+ case email
+ }
+
+ init(from decoder: Decoder) throws {
+ let container = try decoder.container(keyedBy: CodingKeys.self)
+ let type = try container.decode(IntegrationType.self, forKey: .type)
+ switch type {
+ case .webhook:
+ self = .webhook(try container.decode(WebhookIntegrationConfiguration.self, forKey: .webhook))
+ case .slack:
+ self = .slack(try container.decode(SlackIntegrationConfiguration.self, forKey: .slack))
+ case .email:
+ self = .email(try container.decode(EmailIntegrationConfiguration.self, forKey: .email))
+ }
+ }
+
+ func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+ switch self {
+ case .webhook(let configuration):
+ try container.encode(IntegrationType.webhook, forKey: .type)
+ try container.encode(configuration, forKey: .webhook)
+ case .slack(let configuration):
+ try container.encode(IntegrationType.slack, forKey: .type)
+ try container.encode(configuration, forKey: .slack)
+ case .email(let configuration):
+ try container.encode(IntegrationType.email, forKey: .type)
+ try container.encode(configuration, forKey: .email)
+ }
+ }
+
+ var type: IntegrationType {
+ switch self {
+ case .webhook:
+ return .webhook
+ case .slack:
+ return .slack
+ case .email:
+ return .email
+ }
+ }
+}
+
+struct IntegrationFilterSet: Codable, Equatable, Sendable {
+ var minimumSeverity: EventSeverity
+ var eventTypes: Set<MonitoringEventType>
+ var domains: [String]
+
+ init(
+ minimumSeverity: EventSeverity = .warning,
+ eventTypes: Set<MonitoringEventType> = Set(MonitoringEventType.allCases.filter { $0 != .test }),
+ domains: [String] = []
+ ) {
+ self.minimumSeverity = minimumSeverity
+ self.eventTypes = eventTypes
+ self.domains = domains
+ }
+
+ func matches(_ event: MonitoringEvent) -> Bool {
+ guard event.severity >= minimumSeverity else {
+ return false
+ }
+ guard eventTypes.isEmpty || eventTypes.contains(event.type) else {
+ return false
+ }
+ guard domains.isEmpty || domains.map({ $0.lowercased() }).contains(event.domain.lowercased()) else {
+ return false
+ }
+ return true
+ }
+}
+
+struct IntegrationTarget: Codable, Identifiable, Equatable, Sendable {
+ var id: UUID
+ var type: IntegrationType
+ var name: String
+ var isEnabled: Bool
+ var configuration: IntegrationConfiguration
+ var filters: IntegrationFilterSet
+
+ init(
+ id: UUID = UUID(),
+ type: IntegrationType,
+ name: String,
+ isEnabled: Bool = true,
+ configuration: IntegrationConfiguration,
+ filters: IntegrationFilterSet = IntegrationFilterSet()
+ ) {
+ self.id = id
+ self.type = type
+ self.name = name
+ self.isEnabled = isEnabled
+ self.configuration = configuration
+ self.filters = filters
+ }
+}
+
+enum DeliveryStatus: String, Codable, CaseIterable, Identifiable, Sendable {
+ case pending
+ case retrying
+ case delivered
+ case failed
+ case expired
+ case skipped
+
+ var id: String { rawValue }
+
+ var title: String {
+ rawValue.capitalized
+ }
+}
+
+struct DeliveryRecord: Codable, Identifiable, Equatable, Sendable {
+ var id: UUID
+ var integrationID: UUID
+ var eventID: UUID
+ var timestamp: Date
+ var status: DeliveryStatus
+ var destination: String
+ var summary: String
+ var failureReason: String?
+ var attemptCount: Int
+
+ init(
+ id: UUID = UUID(),
+ integrationID: UUID,
+ eventID: UUID,
+ timestamp: Date = Date(),
+ status: DeliveryStatus,
+ destination: String,
+ summary: String,
+ failureReason: String? = nil,
+ attemptCount: Int = 0
+ ) {
+ self.id = id
+ self.integrationID = integrationID
+ self.eventID = eventID
+ self.timestamp = timestamp
+ self.status = status
+ self.destination = destination
+ self.summary = summary
+ self.failureReason = failureReason
+ self.attemptCount = attemptCount
+ }
+}
+
+struct QueuedDelivery: Codable, Identifiable, Equatable, Sendable {
+ var id: UUID
+ var integrationID: UUID
+ var event: MonitoringEvent
+ var createdAt: Date
+ var attemptCount: Int
+ var nextAttemptAt: Date
+ var lastError: String?
+ var expiresAt: Date
+
+ init(
+ id: UUID = UUID(),
+ integrationID: UUID,
+ event: MonitoringEvent,
+ createdAt: Date = Date(),
+ attemptCount: Int = 0,
+ nextAttemptAt: Date = Date(),
+ lastError: String? = nil,
+ expiresAt: Date = Date().addingTimeInterval(3 * 24 * 60 * 60)
+ ) {
+ self.id = id
+ self.integrationID = integrationID
+ self.event = event
+ self.createdAt = createdAt
+ self.attemptCount = attemptCount
+ self.nextAttemptAt = nextAttemptAt
+ self.lastError = lastError
+ self.expiresAt = expiresAt
+ }
+}
+
// MARK: - DNS Models
enum DNSRecordType: String, CaseIterable, Codable {