From 88be632a58f2c26049325a4512af1abe87eda24d Mon Sep 17 00:00:00 2001 From: Tony Arnold Date: Tue, 4 Jul 2023 12:08:39 +1000 Subject: [PATCH 1/2] =?UTF-8?q?Make=20the=20Personalization=E2=80=99s=20dy?= =?UTF-8?q?namicTemplateData=20generic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should allow support for nested Codable structures, and better type support when encoded to JSON. Fixes #7 --- .../SendGridKit/Models/Personalization.swift | 32 +++++++++++-- .../SendGridKit/Models/SendGridEmail.swift | 48 +++++++++++++++++-- Sources/SendGridKit/SendGridClient.swift | 4 +- Tests/SendGridKitTests/SendGridTestsKit.swift | 2 +- 4 files changed, 75 insertions(+), 11 deletions(-) diff --git a/Sources/SendGridKit/Models/Personalization.swift b/Sources/SendGridKit/Models/Personalization.swift index 215bc69..1c5a121 100644 --- a/Sources/SendGridKit/Models/Personalization.swift +++ b/Sources/SendGridKit/Models/Personalization.swift @@ -1,6 +1,6 @@ import Foundation -public struct Personalization: Codable { +public struct Personalization: Codable { /// An array of recipients. Each object within this array may contain the name, but must always contain the email, of a recipient. public var to: [EmailAddress]? @@ -21,8 +21,8 @@ public struct Personalization: Codable { public var substitutions: [String: String]? /// A collection of key/value pairs following the pattern "key":"value" to substitute handlebar template data - public var dynamicTemplateData: [String: String]? - + public var dynamicTemplateData: DynamicTemplateData? + /// Values that are specific to this personalization that will be carried along with the email and its activity data. public var customArgs: [String: String]? @@ -36,7 +36,7 @@ public struct Personalization: Codable { subject: String? = nil, headers: [String: String]? = nil, substitutions: [String: String]? = nil, - dynamicTemplateData: [String: String]? = nil, + dynamicTemplateData: DynamicTemplateData? = nil, customArgs: [String: String]? = nil, sendAt: Date? = nil ) { @@ -64,3 +64,27 @@ public struct Personalization: Codable { } } + +public extension Personalization where DynamicTemplateData == [String: String] { + init( + to: [EmailAddress]? = nil, + cc: [EmailAddress]? = nil, + bcc: [EmailAddress]? = nil, + subject: String? = nil, + headers: [String: String]? = nil, + substitutions: [String: String]? = nil, + dynamicTemplateData: [String: String]? = nil, + customArgs: [String: String]? = nil, + sendAt: Date? = nil + ) { + self.to = to + self.cc = cc + self.bcc = bcc + self.subject = subject + self.headers = headers + self.substitutions = substitutions + self.dynamicTemplateData = dynamicTemplateData + self.customArgs = customArgs + self.sendAt = sendAt + } +} diff --git a/Sources/SendGridKit/Models/SendGridEmail.swift b/Sources/SendGridKit/Models/SendGridEmail.swift index 64691b2..d30bb81 100644 --- a/Sources/SendGridKit/Models/SendGridEmail.swift +++ b/Sources/SendGridKit/Models/SendGridEmail.swift @@ -1,9 +1,9 @@ import Foundation -public struct SendGridEmail: Codable { - +public struct SendGridEmail: Codable { + /// An array of messages and their metadata. Each object within personalizations can be thought of as an envelope - it defines who should receive an individual message and how that message should be handled. - public var personalizations: [Personalization] + public var personalizations: [Personalization] public var from: EmailAddress @@ -52,7 +52,7 @@ public struct SendGridEmail: Codable { public var trackingSettings: TrackingSettings? public init( - personalizations: [Personalization], + personalizations: [Personalization], from: EmailAddress, replyTo: EmailAddress? = nil, replyToList: [EmailAddress]? = nil, @@ -110,3 +110,43 @@ public struct SendGridEmail: Codable { } } + +public extension SendGridEmail where DynamicTemplateData == [String: String] { + init( + personalizations: [Personalization<[String: String]>], + from: EmailAddress, + replyTo: EmailAddress? = nil, + replyToList: [EmailAddress]? = nil, + subject: String? = nil, + content: [EmailContent]? = nil, + attachments: [EmailAttachment]? = nil, + templateId: String? = nil, + headers: [String: String]? = nil, + categories: [String]? = nil, + customArgs: [String: String]? = nil, + sendAt: Date? = nil, + batchId: String? = nil, + asm: AdvancedSuppressionManager? = nil, + ipPoolName: String? = nil, + mailSettings: MailSettings? = nil, + trackingSettings: TrackingSettings? = nil + ) { + self.personalizations = personalizations + self.from = from + self.replyTo = replyTo + self.replyToList = replyToList + self.subject = subject + self.content = content + self.attachments = attachments + self.templateId = templateId + self.headers = headers + self.categories = categories + self.customArgs = customArgs + self.sendAt = sendAt + self.batchId = batchId + self.asm = asm + self.ipPoolName = ipPoolName + self.mailSettings = mailSettings + self.trackingSettings = trackingSettings + } +} diff --git a/Sources/SendGridKit/SendGridClient.swift b/Sources/SendGridKit/SendGridClient.swift index 4ea154a..97775c7 100644 --- a/Sources/SendGridKit/SendGridClient.swift +++ b/Sources/SendGridKit/SendGridClient.swift @@ -27,8 +27,8 @@ public struct SendGridClient { self.apiKey = apiKey } - public func send(email: SendGridEmail) async throws { - + public func send(email: SendGridEmail) async throws { + var headers = HTTPHeaders() headers.add(name: "Authorization", value: "Bearer \(apiKey)") headers.add(name: "Content-Type", value: "application/json") diff --git a/Tests/SendGridKitTests/SendGridTestsKit.swift b/Tests/SendGridKitTests/SendGridTestsKit.swift index 69d3cba..7ac7fd8 100644 --- a/Tests/SendGridKitTests/SendGridTestsKit.swift +++ b/Tests/SendGridKitTests/SendGridTestsKit.swift @@ -24,7 +24,7 @@ class SendGridKitTests: XCTestCase { // TODO: Replace to address with the email address you'd like to recieve your test email! let personalization = Personalization(to: ["TO-ADDRESS"]) - + // TODO: Replace from address with the email address associated with your verified Sender Identity! let email = SendGridEmail( personalizations: [personalization], From 35478667a1244d9dd5942db17fc82f9659c4893e Mon Sep 17 00:00:00 2001 From: Francesco Paolo Severino Date: Sat, 21 Sep 2024 11:34:20 +0200 Subject: [PATCH 2/2] Add some `init`s and tests --- Sources/SendGridKit/Models/MailSettings.swift | 4 ++++ .../SendGridKit/Models/TrackingSettings.swift | 5 +++++ Tests/SendGridKitTests/SendGridTestsKit.swift | 22 ++++++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Sources/SendGridKit/Models/MailSettings.swift b/Sources/SendGridKit/Models/MailSettings.swift index 35b7df7..de1463c 100644 --- a/Sources/SendGridKit/Models/MailSettings.swift +++ b/Sources/SendGridKit/Models/MailSettings.swift @@ -50,6 +50,10 @@ public struct MailSettings: Codable, Sendable { public struct Setting: Codable, Sendable { /// Indicates if this setting is enabled. public var enable: Bool + + public init(enable: Bool) { + self.enable = enable + } } public struct Footer: Codable, Sendable { diff --git a/Sources/SendGridKit/Models/TrackingSettings.swift b/Sources/SendGridKit/Models/TrackingSettings.swift index 1d06306..4a1bb34 100644 --- a/Sources/SendGridKit/Models/TrackingSettings.swift +++ b/Sources/SendGridKit/Models/TrackingSettings.swift @@ -44,6 +44,11 @@ public struct ClickTracking: Codable, Sendable { /// Indicates if this setting should be included in the text/plain portion of your email. public var enableText: Bool + + public init(enable: Bool, enableText: Bool) { + self.enable = enable + self.enableText = enableText + } private enum CodingKeys: String, CodingKey { case enable diff --git a/Tests/SendGridKitTests/SendGridTestsKit.swift b/Tests/SendGridKitTests/SendGridTestsKit.swift index 972fa94..3c23cdc 100644 --- a/Tests/SendGridKitTests/SendGridTestsKit.swift +++ b/Tests/SendGridKitTests/SendGridTestsKit.swift @@ -1,6 +1,6 @@ import Testing import AsyncHTTPClient -@testable import SendGridKit +import SendGridKit struct SendGridKitTests { var client: SendGridClient @@ -74,4 +74,24 @@ struct SendGridKitTests { true } } + + @Test func dynamicTemplateData() async throws { + struct DynamicTemplateData: Codable, Sendable { + let text: String + let integer: Int + let double: Double + } + let dynamicTemplateData = DynamicTemplateData(text: "Hello, World!", integer: 42, double: 3.14) + + // TODO: Replace the addresses with real email addresses + let personalization = Personalization(to: [EmailAddress("TO-ADDRESS")], subject: "Test Email", dynamicTemplateData: dynamicTemplateData) + let email = SendGridEmail(personalizations: [personalization], from: EmailAddress("FROM-ADDRESS"), content: [EmailContent("Hello, World!")]) + + try await withKnownIssue { + try await client.send(email: email) + } when: { + // TODO: Replace with `false` when you have a valid API key + true + } + } }