diff --git a/.spi.yml b/.spi.yml new file mode 100644 index 0000000..bb99af5 --- /dev/null +++ b/.spi.yml @@ -0,0 +1,4 @@ +version: 1 +builder: + configs: + - documentation_targets: [Passes] \ No newline at end of file diff --git a/Package.swift b/Package.swift index 6a83a59..63291a0 100644 --- a/Package.swift +++ b/Package.swift @@ -13,7 +13,7 @@ let package = Package( .package(url: "https://github.com/vapor/vapor.git", from: "4.102.0"), .package(url: "https://github.com/vapor/fluent.git", from: "4.11.0"), .package(url: "https://github.com/vapor/apns.git", from: "4.1.0"), - .package(url: "https://github.com/apple/swift-log.git", from: "1.6.0") + .package(url: "https://github.com/apple/swift-log.git", from: "1.6.0"), ], targets: [ .target( @@ -22,7 +22,7 @@ let package = Package( .product(name: "Fluent", package: "fluent"), .product(name: "Vapor", package: "vapor"), .product(name: "VaporAPNS", package: "apns"), - .product(name: "Logging", package: "swift-log") + .product(name: "Logging", package: "swift-log"), ], swiftSettings: swiftSettings ), diff --git a/README.md b/README.md index 92a0232..1e82318 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ app.apns.containers.use( eventLoopGroupProvider: .shared(app.eventLoopGroup), responseDecoder: JSONDecoder(), requestEncoder: JSONEncoder(), - as: .init(string: "passkit"), + as: .init(string: "passes"), isDefault: false ) ``` diff --git a/Sources/Passes/Models/ConcreteModels.swift b/Sources/Passes/Models/ConcreteModels.swift index 364ce44..f6c7bea 100644 --- a/Sources/Passes/Models/ConcreteModels.swift +++ b/Sources/Passes/Models/ConcreteModels.swift @@ -29,6 +29,7 @@ import Vapor import Fluent +/// The `Model` that stores PassKit devices. final public class PKDevice: PassKitDevice, @unchecked Sendable { public static let schema = "devices" @@ -64,6 +65,7 @@ extension PKDevice: AsyncMigration { } } +/// The `Model` that stores PassKit passes. open class PKPass: PassKitPass, @unchecked Sendable { public static let schema = "passes" @@ -97,6 +99,7 @@ extension PKPass: AsyncMigration { } } +/// The `Model` that stores PassKit error logs. final public class PKErrorLog: PassKitErrorLog, @unchecked Sendable { public static let schema = "errors" @@ -130,6 +133,7 @@ extension PKErrorLog: AsyncMigration { } } +/// The `Model` that stores PassKit registrations. final public class PKRegistration: PassKitRegistration, @unchecked Sendable { public typealias PassType = PKPass public typealias DeviceType = PKDevice diff --git a/Sources/Passes/Models/PassKitPass.swift b/Sources/Passes/Models/PassKitPass.swift index 631cc07..6f4e174 100644 --- a/Sources/Passes/Models/PassKitPass.swift +++ b/Sources/Passes/Models/PassKitPass.swift @@ -29,7 +29,7 @@ import Vapor import Fluent -/// Represents the `Model` that stores PassKit passes. Uses a UUID so people can't easily guess your pass IDs +/// Represents the `Model` that stores PassKit passes. Uses a UUID so people can't easily guess pass IDs public protocol PassKitPass: Model where IDValue == UUID { /// The pass type identifier. var passTypeIdentifier: String { get set } diff --git a/Sources/Passes/Models/PassKitPassData.swift b/Sources/Passes/Models/PassKitPassData.swift index 68f470b..cf419a2 100644 --- a/Sources/Passes/Models/PassKitPassData.swift +++ b/Sources/Passes/Models/PassKitPassData.swift @@ -29,6 +29,7 @@ import Vapor import Fluent +/// Represents the `Model` that stores custom app data associated to PassKit passes. public protocol PassKitPassData: Model { associatedtype PassType: PassKitPass diff --git a/Sources/Passes/Passes.swift b/Sources/Passes/Passes.swift index abdafb9..13277ce 100644 --- a/Sources/Passes/Passes.swift +++ b/Sources/Passes/Passes.swift @@ -33,6 +33,7 @@ import VaporAPNS import Fluent import NIOSSL +/// The main class that handles PassKit passes. public final class Passes: Sendable { private let kit: PassesCustom @@ -47,14 +48,26 @@ public final class Passes: Sendable { kit.registerRoutes(authorizationCode: authorizationCode) } + /// Registers routes to send push notifications to updated passes. + /// + /// - Parameter middleware: The `Middleware` which will control authentication for the routes. public func registerPushRoutes(middleware: any Middleware) throws { try kit.registerPushRoutes(middleware: middleware) } + /// Generates the pass content bundle for a given pass. + /// + /// - Parameters: + /// - pass: The pass to generate the content for. + /// - db: The `Database` to use. + /// - Returns: The generated pass content. public func generatePassContent(for pass: PKPass, on db: any Database) async throws -> Data { try await kit.generatePassContent(for: pass, on: db) } + /// Adds the migrations for PassKit passes models. + /// + /// - Parameter migrations: The `Migrations` object to add the migrations to. public static func register(migrations: Migrations) { migrations.add(PKPass()) migrations.add(PKDevice()) @@ -62,20 +75,39 @@ public final class Passes: Sendable { migrations.add(PKErrorLog()) } - public static func sendPushNotificationsForPass(id: UUID, of type: String, on db: any Database, app: Application) async throws { - try await PassesCustom.sendPushNotificationsForPass(id: id, of: type, on: db, app: app) + /// Sends push notifications for a given pass. + /// + /// - Parameters: + /// - id: The `UUID` of the pass to send the notifications for. + /// - passTypeIdentifier: The type identifier of the pass. + /// - db: The `Database` to use. + /// - app: The `Application` to use. + public static func sendPushNotificationsForPass(id: UUID, of passTypeIdentifier: String, on db: any Database, app: Application) async throws { + try await PassesCustom.sendPushNotificationsForPass(id: id, of: passTypeIdentifier, on: db, app: app) } + /// Sends push notifications for a given pass. + /// + /// - Parameters: + /// - pass: The pass to send the notifications for. + /// - db: The `Database` to use. + /// - app: The `Application` to use. public static func sendPushNotifications(for pass: PKPass, on db: any Database, app: Application) async throws { try await PassesCustom.sendPushNotifications(for: pass, on: db, app: app) } + /// Sends push notifications for a given pass. + /// + /// - Parameters: + /// - pass: The pass (as the `ParentProperty`) to send the notifications for. + /// - db: The `Database` to use. + /// - app: The `Application` to use. public static func sendPushNotifications(for pass: ParentProperty, on db: any Database, app: Application) async throws { try await PassesCustom.sendPushNotifications(for: pass, on: db, app: app) } } -/// Class to handle Passes. +/// Class to handle `Passes`. /// /// The generics should be passed in this order: /// - Pass Type @@ -102,7 +134,7 @@ public final class PassesCustom PassesForDeviceDTO { logger?.debug("Called passesForDevice") - let type = req.parameters.get("type")! + let passTypeIdentifier = req.parameters.get("passTypeIdentifier")! let deviceLibraryIdentifier = req.parameters.get("deviceLibraryIdentifier")! - var query = R.for(deviceLibraryIdentifier: deviceLibraryIdentifier, passTypeIdentifier: type, on: req.db) + var query = R.for(deviceLibraryIdentifier: deviceLibraryIdentifier, passTypeIdentifier: passTypeIdentifier, on: req.db) if let since: TimeInterval = req.query["passesUpdatedSince"] { let when = Date(timeIntervalSince1970: since) @@ -263,7 +295,7 @@ public final class PassesCustom HTTPStatus { logger?.debug("Called unregisterDevice") - let type = req.parameters.get("type")! + let passTypeIdentifier = req.parameters.get("passTypeIdentifier")! guard let passId = req.parameters.get("passSerial", as: UUID.self) else { throw Abort(.badRequest) @@ -302,7 +334,7 @@ public final class PassesCustom