diff --git a/Sources/OneSignal/OneSignal.swift b/Sources/OneSignal/OneSignal.swift index 199be2a..22054a3 100644 --- a/Sources/OneSignal/OneSignal.swift +++ b/Sources/OneSignal/OneSignal.swift @@ -25,9 +25,9 @@ public final class OneSignal { } /// Send the message - public func send(notification: OneSignalNotification, toApp app: OneSignalApp) throws -> EventLoopFuture { - return try self.sendRaw(notification: notification, toApp: app).map { response in - guard var responseBody = response.body, let body = responseBody.readBytes(length: responseBody.readableBytes) else { + public func send(notification: OneSignalNotification, toApp app: OneSignalApp, method: OneSignalNotification.Method) throws -> Future { + return try self.client.send(notification.generateRequest(on: self.worker, for: app, method: method)).map(to: OneSignalResult.self) { response in + guard let body = response.http.body.data else { return OneSignalResult.error(error: OneSignalError.internal) } @@ -41,7 +41,7 @@ public final class OneSignal { } } - public func sendRaw(notification: OneSignalNotification, toApp app: OneSignalApp) throws -> EventLoopFuture { - return try self.httpClient.execute(request: notification.generateRequest(for: app)) + public func sendRaw(notification: OneSignalNotification, toApp app: OneSignalApp, method: OneSignalNotification.Method) throws -> Future { + return try self.client.send(notification.generateRequest(on: self.worker, for: app, method: method)) } } diff --git a/Sources/OneSignal/OneSignalNotification.swift b/Sources/OneSignal/OneSignalNotification.swift index bc6d848..dd35c91 100644 --- a/Sources/OneSignal/OneSignalNotification.swift +++ b/Sources/OneSignal/OneSignalNotification.swift @@ -9,10 +9,43 @@ import AsyncHTTPClient import Foundation public struct OneSignalNotification: Codable { + public enum Method { + case players(_ playersId: [String], iosDeviceTokens: [String]?) + /** + playersId: [String] + RECOMMENDED - Specific players to send your notification to. Does not require API Auth Key. + Do not combine with other targeting parameters. Not compatible with any other targeting parameters. + + Example: `["1dd608f2-c6a1-11e3-851d-000c2940e62c"]` + + iosDeviceTokens: [String]? + NOT RECOMMENDED - Please consider using include_player_ids instead. + Target using iOS device tokens. Warning: Only works with Production tokens. + All non-alphanumeric characters must be removed from each token. If a token does not correspond + to an existing user, a new user will be created. + + Example: `ce777617da7f548fe7a9ab6febb56cf39fba6d38203...` + */ + + case segments(_ included: [String], excluded: [String]?) + /** + included: [String] + The segment names you want to target. + Users in these segments will receive a notification. + This targeting parameter is only compatible with excluded_segments. + + Example: ["Active Users", "Inactive Users"] + + excluded: [String]? + Segment that will be excluded when sending. + Users in these segments will not receive a notification, even if they were included in included_segments. + This targeting parameter is only compatible with included_segments. + + Example: ["Active Users", "Inactive Users"] + */ + } + enum CodingKeys: String, CodingKey { - case users - case deviceTokens - case title case subtitle case message @@ -28,24 +61,6 @@ public struct OneSignalNotification: Codable { case isContentMutable = "mutable_content" } - /** - RECOMMENDED - Specific players to send your notification to. Does not require API Auth Key. - Do not combine with other targeting parameters. Not compatible with any other targeting parameters. - - Example: `["1dd608f2-c6a1-11e3-851d-000c2940e62c"]` - */ - public var users: [String] = [] - - /** - NOT RECOMMENDED - Please consider using include_player_ids instead. - Target using iOS device tokens. Warning: Only works with Production tokens. - All non-alphanumeric characters must be removed from each token. If a token does not correspond - to an existing user, a new user will be created. - - Example: `ce777617da7f548fe7a9ab6febb56cf39fba6d38203...` - */ - public var deviceTokens: [String]? - /** The notification's title, a map of language codes to text for each language. Each hash must have a language code string for a key, mapped to the localized text you would like users to receive for that language. @@ -138,29 +153,16 @@ public struct OneSignalNotification: Codable { public init(message: String) { self.message = OneSignalMessage(message) - self.users = [] } public init(message: OneSignalMessage) { self.message = message - self.users = [] } - public init(message: String, users: [String]) { - self.message = OneSignalMessage(message) - self.users = users - } - - public init(message: OneSignalMessage, users: [String]) { - self.message = message - self.users = users - } - - public init(title: String?, subtitle: String?, body: String, users: [String], deviceTokens: [String]? = nil, sound: String? = nil, category: String? = nil, sendAfter: String? = nil, additionalData: [String: String]? = nil, attachments: [String: String]? = nil) { + public init(title: String?, subtitle: String?, body: String, sound: String? = nil, category: String? = nil, sendAfter: String? = nil, additionalData: [String : String]? = nil, attachments: [String : String]? = nil) { if let title = title { self.title = OneSignalMessage(title) } if let subtitle = subtitle { self.subtitle = OneSignalMessage(subtitle) } self.message = OneSignalMessage(body) - self.users = users self.sound = sound self.category = category self.sendAfter = sendAfter @@ -170,10 +172,6 @@ public struct OneSignalNotification: Codable { } extension OneSignalNotification { - public mutating func addUser(_ id: String) { - self.users.append(id) - } - public mutating func addMessage(_ message: String, language: String = "en") { self.message[language] = message } @@ -206,15 +204,38 @@ extension OneSignalNotification { } extension OneSignalNotification { - internal func generateRequest(for app: OneSignalApp) throws -> HTTPClient.Request { - guard let url = URL(string: "https://onesignal.com/api/v1/notifications") else { - throw OneSignalError.invalidURL + internal func generateRequest(on container: Container, for app: OneSignalApp, method: Method) throws -> Request { + let request = Request(using: container) + request.http.method = .POST + + request.http.headers.add(name: .connection, value: "Keep-Alive") + request.http.headers.add(name: .authorization, value: "Basic \(app.apiKey)") + request.http.headers.add(name: .contentType, value: "application/json") + + let playerIds: [String]? + let iosDeviceTokens: [String]? + let segments: [String]? + let excludedSegments: [String]? + + switch method { + case let .players(ids, tokens): + playerIds = ids + iosDeviceTokens = tokens + segments = nil + excludedSegments = nil + case let .segments(included, excluded): + segments = included + excludedSegments = excluded + playerIds = nil + iosDeviceTokens = nil } let payload = OneSignalPayload( appId: app.appId, - playerIds: self.users, - iosDeviceTokens: self.deviceTokens, + playerIds: playerIds, + iosDeviceTokens: iosDeviceTokens, + segments: segments, + excludedSegments: excludedSegments, contents: self.message.messages, headings: self.title?.messages, subtitle: self.subtitle?.messages, diff --git a/Sources/OneSignal/OneSignalPayload.swift b/Sources/OneSignal/OneSignalPayload.swift index 35956d0..e7c0b00 100644 --- a/Sources/OneSignal/OneSignalPayload.swift +++ b/Sources/OneSignal/OneSignalPayload.swift @@ -13,6 +13,8 @@ public struct OneSignalPayload: Encodable { case appId = "app_id" case playerIds = "include_player_ids" case iosDeviceTokens = "include_ios_tokens" + case segments = "included_segments" + case excludedSegments = "excluded_segments" case contents case headings @@ -30,12 +32,13 @@ public struct OneSignalPayload: Encodable { } public var appId: String - - public var playerIds: [String] + + public var playerIds: [String]? public var iosDeviceTokens: [String]? - + public var segments: [String]? + public var excludedSegments: [String]? + public var contents: [String: String] - public var headings: [String: String]? public var subtitle: [String: String]?