Fixed Swift compilation errors preventing iOS build: - Added explicit self capture [self] in closures in DailyNotificationReactivationManager - Removed invalid BGTaskScheduler.shared.registeredTaskIdentifiers API call - Fixed initialization order in DailyNotificationModel (verifyEntities after container init) Added missing configureNativeFetcher method to iOS plugin: - Implemented method matching Android functionality - Stores configuration in UserDefaults for persistence - Registered method in pluginMethods array - Supports both jwtToken and jwtSecret parameters for compatibility This resolves the runtime error "configureNativeFetcher is not a function" that was preventing the test app from configuring the plugin.
412 lines
13 KiB
Swift
412 lines
13 KiB
Swift
/**
|
|
* NotificationConfigDAO.swift
|
|
*
|
|
* Data Access Object (DAO) for NotificationConfig Core Data entity
|
|
* Provides CRUD operations and query helpers for notification configuration
|
|
*
|
|
* @author Matthew Raymer
|
|
* @version 1.0.0
|
|
* @created 2025-12-08
|
|
*/
|
|
|
|
import Foundation
|
|
import CoreData
|
|
|
|
/**
|
|
* Extension providing DAO methods for NotificationConfig entity
|
|
*
|
|
* This extension adds CRUD operations and query helpers to the
|
|
* auto-generated NotificationConfig Core Data class.
|
|
*/
|
|
extension NotificationConfig {
|
|
|
|
// MARK: - Constants
|
|
|
|
private static let TAG = "DNP-NOTIFICATION-CONFIG-DAO"
|
|
|
|
// MARK: - Create/Insert Methods
|
|
|
|
/**
|
|
* Create a new NotificationConfig entity in the given context
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param id Unique configuration identifier
|
|
* @param timesafariDid TimeSafari device ID
|
|
* @param configType Type of configuration
|
|
* @param configKey Configuration key
|
|
* @param configValue Configuration value (string representation)
|
|
* @param configDataType Data type of value (e.g., "string", "int", "bool", "json")
|
|
* @param isEncrypted Whether value is encrypted
|
|
* @param encryptionKeyId Encryption key identifier
|
|
* @param ttlSeconds Time-to-live in seconds
|
|
* @param isActive Whether configuration is active
|
|
* @param metadata Additional metadata (JSON string)
|
|
* @return Created NotificationConfig entity
|
|
*/
|
|
static func create(
|
|
in context: NSManagedObjectContext,
|
|
id: String,
|
|
timesafariDid: String? = nil,
|
|
configType: String? = nil,
|
|
configKey: String? = nil,
|
|
configValue: String? = nil,
|
|
configDataType: String? = nil,
|
|
isEncrypted: Bool = false,
|
|
encryptionKeyId: String? = nil,
|
|
ttlSeconds: Int64 = 604800, // 7 days default
|
|
isActive: Bool = true,
|
|
metadata: String? = nil
|
|
) -> NotificationConfig {
|
|
let entity = NotificationConfig(context: context)
|
|
let now = Date()
|
|
|
|
entity.id = id
|
|
entity.timesafariDid = timesafariDid
|
|
entity.configType = configType
|
|
entity.configKey = configKey
|
|
entity.configValue = configValue
|
|
entity.configDataType = configDataType
|
|
entity.isEncrypted = isEncrypted
|
|
entity.encryptionKeyId = encryptionKeyId
|
|
entity.createdAt = now
|
|
entity.updatedAt = now
|
|
entity.ttlSeconds = ttlSeconds
|
|
entity.isActive = isActive
|
|
entity.metadata = metadata
|
|
|
|
print("\(Self.TAG): Created NotificationConfig with id: \(id)")
|
|
return entity
|
|
}
|
|
|
|
/**
|
|
* Create from dictionary representation
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param dict Dictionary with configuration data
|
|
* @return Created NotificationConfig entity or nil
|
|
*/
|
|
static func create(
|
|
in context: NSManagedObjectContext,
|
|
from dict: [String: Any]
|
|
) -> NotificationConfig? {
|
|
guard let id = dict["id"] as? String else {
|
|
print("\(Self.TAG): Missing required 'id' field")
|
|
return nil
|
|
}
|
|
|
|
// Convert createdAt/updatedAt if present
|
|
let createdAt: Date
|
|
if let createdMillis = dict["createdAt"] as? Int64 {
|
|
createdAt = DailyNotificationDataConversions.dateFromEpochMillis(createdMillis)
|
|
} else if let createdDate = dict["createdAt"] as? Date {
|
|
createdAt = createdDate
|
|
} else {
|
|
createdAt = Date()
|
|
}
|
|
|
|
let updatedAt: Date
|
|
if let updatedMillis = dict["updatedAt"] as? Int64 {
|
|
updatedAt = DailyNotificationDataConversions.dateFromEpochMillis(updatedMillis)
|
|
} else if let updatedDate = dict["updatedAt"] as? Date {
|
|
updatedAt = updatedDate
|
|
} else {
|
|
updatedAt = Date()
|
|
}
|
|
|
|
let entity = NotificationConfig(context: context)
|
|
entity.id = id
|
|
entity.timesafariDid = dict["timesafariDid"] as? String
|
|
entity.configType = dict["configType"] as? String
|
|
entity.configKey = dict["configKey"] as? String
|
|
entity.configValue = dict["configValue"] as? String
|
|
entity.configDataType = dict["configDataType"] as? String
|
|
entity.isEncrypted = dict["isEncrypted"] as? Bool ?? false
|
|
entity.encryptionKeyId = dict["encryptionKeyId"] as? String
|
|
entity.createdAt = createdAt
|
|
entity.updatedAt = updatedAt
|
|
entity.ttlSeconds = dict["ttlSeconds"] as? Int64 ?? 604800
|
|
entity.isActive = dict["isActive"] as? Bool ?? true
|
|
entity.metadata = dict["metadata"] as? String
|
|
|
|
return entity
|
|
}
|
|
|
|
// MARK: - Read/Query Methods
|
|
|
|
/**
|
|
* Fetch NotificationConfig by ID
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param id Configuration ID
|
|
* @return NotificationConfig entity or nil
|
|
*/
|
|
static func fetch(
|
|
by id: String,
|
|
in context: NSManagedObjectContext
|
|
) -> NotificationConfig? {
|
|
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
|
|
request.predicate = NSPredicate(format: "id == %@", id)
|
|
request.fetchLimit = 1
|
|
|
|
do {
|
|
let results = try context.fetch(request)
|
|
return results.first
|
|
} catch {
|
|
print("\(Self.TAG): Error fetching by id: \(error.localizedDescription)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch NotificationConfig by key (configKey)
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param configKey Configuration key
|
|
* @return NotificationConfig entity or nil
|
|
*/
|
|
static func fetchByConfigKey(
|
|
_ configKey: String,
|
|
in context: NSManagedObjectContext
|
|
) -> NotificationConfig? {
|
|
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
|
|
request.predicate = NSPredicate(format: "configKey == %@", configKey)
|
|
request.fetchLimit = 1
|
|
|
|
do {
|
|
let results = try context.fetch(request)
|
|
return results.first
|
|
} catch {
|
|
print("\(Self.TAG): Error fetching by configKey: \(error.localizedDescription)")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch all NotificationConfig entities
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @return Array of NotificationConfig entities
|
|
*/
|
|
static func fetchAll(
|
|
in context: NSManagedObjectContext
|
|
) -> [NotificationConfig] {
|
|
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
|
|
|
|
do {
|
|
return try context.fetch(request)
|
|
} catch {
|
|
print("\(Self.TAG): Error fetching all: \(error.localizedDescription)")
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Query by timesafariDid
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param timesafariDid TimeSafari device ID
|
|
* @return Array of NotificationConfig entities
|
|
*/
|
|
static func queryByTimesafariDid(
|
|
_ timesafariDid: String,
|
|
in context: NSManagedObjectContext
|
|
) -> [NotificationConfig] {
|
|
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
|
|
request.predicate = NSPredicate(format: "timesafariDid == %@", timesafariDid)
|
|
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
|
|
|
|
do {
|
|
return try context.fetch(request)
|
|
} catch {
|
|
print("\(Self.TAG): Error querying by timesafariDid: \(error.localizedDescription)")
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Query by configType
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param configType Configuration type
|
|
* @return Array of NotificationConfig entities
|
|
*/
|
|
static func queryByConfigType(
|
|
_ configType: String,
|
|
in context: NSManagedObjectContext
|
|
) -> [NotificationConfig] {
|
|
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
|
|
request.predicate = NSPredicate(format: "configType == %@", configType)
|
|
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
|
|
|
|
do {
|
|
return try context.fetch(request)
|
|
} catch {
|
|
print("\(Self.TAG): Error querying by configType: \(error.localizedDescription)")
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Query active configurations only
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @return Array of active NotificationConfig entities
|
|
*/
|
|
static func queryActive(
|
|
in context: NSManagedObjectContext
|
|
) -> [NotificationConfig] {
|
|
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
|
|
request.predicate = NSPredicate(format: "isActive == YES")
|
|
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
|
|
|
|
do {
|
|
return try context.fetch(request)
|
|
} catch {
|
|
print("\(Self.TAG): Error querying active: \(error.localizedDescription)")
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Query by configType and isActive
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param configType Configuration type
|
|
* @param isActive Whether configuration is active
|
|
* @return Array of NotificationConfig entities
|
|
*/
|
|
static func query(
|
|
by configType: String,
|
|
isActive: Bool,
|
|
in context: NSManagedObjectContext
|
|
) -> [NotificationConfig] {
|
|
let request: NSFetchRequest<NotificationConfig> = NotificationConfig.fetchRequest()
|
|
request.predicate = NSPredicate(
|
|
format: "configType == %@ AND isActive == %@",
|
|
configType,
|
|
NSNumber(value: isActive)
|
|
)
|
|
request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
|
|
|
|
do {
|
|
return try context.fetch(request)
|
|
} catch {
|
|
print("\(Self.TAG): Error querying by configType and isActive: \(error.localizedDescription)")
|
|
return []
|
|
}
|
|
}
|
|
|
|
// MARK: - Update Methods
|
|
|
|
/**
|
|
* Update configuration value
|
|
*
|
|
* @param value New configuration value
|
|
*/
|
|
func updateValue(_ value: String?) {
|
|
self.configValue = value
|
|
self.updatedAt = Date()
|
|
}
|
|
|
|
/**
|
|
* Activate or deactivate configuration
|
|
*
|
|
* @param active Whether configuration should be active
|
|
*/
|
|
func setActive(_ active: Bool) {
|
|
self.isActive = active
|
|
self.updatedAt = Date()
|
|
}
|
|
|
|
/**
|
|
* Update this entity's updatedAt timestamp
|
|
*/
|
|
func touch() {
|
|
self.updatedAt = Date()
|
|
}
|
|
|
|
// MARK: - Delete Methods
|
|
|
|
/**
|
|
* Delete NotificationConfig by ID
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param id Configuration ID
|
|
* @return true if deleted, false otherwise
|
|
*/
|
|
static func delete(
|
|
by id: String,
|
|
in context: NSManagedObjectContext
|
|
) -> Bool {
|
|
guard let entity = fetch(by: id, in: context) else {
|
|
return false
|
|
}
|
|
|
|
context.delete(entity)
|
|
|
|
do {
|
|
try context.save()
|
|
print("\(Self.TAG): Deleted NotificationConfig with id: \(id)")
|
|
return true
|
|
} catch {
|
|
print("\(Self.TAG): Error deleting: \(error.localizedDescription)")
|
|
context.rollback()
|
|
return false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete NotificationConfig by configKey
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @param configKey Configuration key
|
|
* @return true if deleted, false otherwise
|
|
*/
|
|
static func deleteByConfigKey(
|
|
_ configKey: String,
|
|
in context: NSManagedObjectContext
|
|
) -> Bool {
|
|
guard let entity = fetchByConfigKey(configKey, in: context) else {
|
|
return false
|
|
}
|
|
|
|
context.delete(entity)
|
|
|
|
do {
|
|
try context.save()
|
|
print("\(Self.TAG): Deleted NotificationConfig with configKey: \(configKey)")
|
|
return true
|
|
} catch {
|
|
print("\(Self.TAG): Error deleting: \(error.localizedDescription)")
|
|
context.rollback()
|
|
return false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete all NotificationConfig entities
|
|
*
|
|
* @param context Core Data managed object context
|
|
* @return Number of entities deleted
|
|
*/
|
|
static func deleteAll(
|
|
in context: NSManagedObjectContext
|
|
) -> Int {
|
|
let request: NSFetchRequest<NSFetchRequestResult> = NotificationConfig.fetchRequest()
|
|
let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
|
|
|
|
do {
|
|
let result = try context.execute(deleteRequest) as? NSBatchDeleteResult
|
|
try context.save()
|
|
let count = result?.result as? Int ?? 0
|
|
print("\(Self.TAG): Deleted \(count) NotificationConfig entities")
|
|
return count
|
|
} catch {
|
|
print("\(Self.TAG): Error deleting all: \(error.localizedDescription)")
|
|
context.rollback()
|
|
return 0
|
|
}
|
|
}
|
|
}
|
|
|