diff --git a/Snippets/PassData.swift b/Snippets/PassData.swift index 37cd6b8..0460d34 100644 --- a/Snippets/PassData.swift +++ b/Snippets/PassData.swift @@ -60,7 +60,7 @@ extension PassData { func personalizationJSON(on db: any Database) async throws -> PersonalizationJSON? { let pass = try await self.$pass.get(on: db) - let personalization = try await Personalization.query(on: db) + let personalization = try await PersonalizationInfo.query(on: db) .filter(\.$pass.$id == pass.requireID()) .first() diff --git a/Sources/FluentWalletPasses/FluentWalletPasses.docc/FluentWalletPasses.md b/Sources/FluentWalletPasses/FluentWalletPasses.docc/FluentWalletPasses.md index b298494..acda38f 100644 --- a/Sources/FluentWalletPasses/FluentWalletPasses.docc/FluentWalletPasses.md +++ b/Sources/FluentWalletPasses/FluentWalletPasses.docc/FluentWalletPasses.md @@ -43,7 +43,7 @@ For information on Apple Wallet passes, see the [Apple Developer Documentation]( ### Personalized Passes - -- ``PersonalizationModel`` -- ``Personalization`` -- ``CreatePersonalization`` +- ``PersonalizationInfoModel`` +- ``PersonalizationInfo`` +- ``CreatePersonalizationInfo`` - ``PersonalizationDictionaryDTO`` diff --git a/Sources/FluentWalletPasses/FluentWalletPasses.docc/PersonalizedPasses.md b/Sources/FluentWalletPasses/FluentWalletPasses.docc/PersonalizedPasses.md index d44a10a..92b73d5 100644 --- a/Sources/FluentWalletPasses/FluentWalletPasses.docc/PersonalizedPasses.md +++ b/Sources/FluentWalletPasses/FluentWalletPasses.docc/PersonalizedPasses.md @@ -28,8 +28,8 @@ If the pass requires personalization, and if it was not already personalized, cr In the ``PassDataModel/sourceFilesDirectoryPath(on:)`` method, you have to return two different directory paths, depending on whether the pass has to be personalized or not. If it does, the directory must contain the `personalizationLogo@XX.png` file. -Finally, you have to implement the ``PassDataModel/passJSON(on:)`` method as usual, but remember to use in the `PassJSON.Properties` initializer the user info that will be saved inside ``Personalization`` after the pass has been personalized. -Each ``Personalization`` instance has a reference to the pass it belongs to, so you can easily retrieve the user info for the pass. +Finally, you have to implement the ``PassDataModel/passJSON(on:)`` method as usual, but remember to use in the `PassJSON.Properties` initializer the user info that will be saved inside ``PersonalizationInfo`` after the pass has been personalized. +Each ``PersonalizationInfo`` instance has a reference to the pass it belongs to, so you can easily retrieve the user info for the pass. ### Implement the Web Service @@ -39,12 +39,12 @@ Build the pass bundle with a `PassBuilder` as usual and distribute it. The user will be prompted to provide the required personal information when they add the pass. -Wallet will then send the user personal information to your server, which should be saved in the ``Personalization`` table, along with a personalization token that you have to sign and return to Wallet in the response. +Wallet will then send the user personal information to your server, which should be saved in the ``PersonalizationInfo`` table, along with a personalization token that you have to sign and return to Wallet in the response. You can use the `PassBuilder.signature(for:)` method to sign the personalization token. Immediately after that, Wallet will request the updated pass. -This updated pass will contain the user personalization data that was previously saved inside the ``Personalization`` table. -You can access the pass linked to the personalization data by using the ``Personalization/pass`` field. +This updated pass will contain the user personalization data that was previously saved inside the ``PersonalizationInfo`` table. +You can access the pass linked to the personalization data by using the ``PersonalizationInfo/pass`` field. > Important: This updated and personalized pass **must not** contain the `personalization.json` file, so make sure that the ``PassDataModel/personalizationJSON(on:)`` method returns `nil` when the pass has already been personalized. diff --git a/Sources/FluentWalletPasses/Models/Concrete Models/Personalization.swift b/Sources/FluentWalletPasses/Models/Concrete Models/PersonalizationInfo.swift similarity index 59% rename from Sources/FluentWalletPasses/Models/Concrete Models/Personalization.swift rename to Sources/FluentWalletPasses/Models/Concrete Models/PersonalizationInfo.swift index 50dd710..8299fac 100644 --- a/Sources/FluentWalletPasses/Models/Concrete Models/Personalization.swift +++ b/Sources/FluentWalletPasses/Models/Concrete Models/PersonalizationInfo.swift @@ -1,83 +1,83 @@ import FluentKit /// The `Model` that stores user personalization info. -final public class Personalization: PersonalizationModel, @unchecked Sendable { +final public class PersonalizationInfo: PersonalizationInfoModel, @unchecked Sendable { /// The schema name of the user personalization model. - public static let schema = Personalization.FieldKeys.schemaName + public static let schema = PersonalizationInfo.FieldKeys.schemaName @ID(custom: .id) public var id: Int? /// The pass this personalization info is associated with. - @Parent(key: Personalization.FieldKeys.passID) + @Parent(key: PersonalizationInfo.FieldKeys.passID) public var pass: Pass /// The user’s full name, as entered by the user. - @OptionalField(key: Personalization.FieldKeys.fullName) + @OptionalField(key: PersonalizationInfo.FieldKeys.fullName) public var fullName: String? /// The user’s given name, parsed from the full name. /// /// This is the name bestowed upon an individual to differentiate them from other members of a group that share a family name (for example, “John”). /// In some locales, this is also known as a first name or forename. - @OptionalField(key: Personalization.FieldKeys.givenName) + @OptionalField(key: PersonalizationInfo.FieldKeys.givenName) public var givenName: String? /// The user’s family name, parsed from the full name. /// /// This is the name bestowed upon an individual to denote membership in a group or family (for example, “Appleseed”). - @OptionalField(key: Personalization.FieldKeys.familyName) + @OptionalField(key: PersonalizationInfo.FieldKeys.familyName) public var familyName: String? /// The email address, as entered by the user. - @OptionalField(key: Personalization.FieldKeys.emailAddress) + @OptionalField(key: PersonalizationInfo.FieldKeys.emailAddress) public var emailAddress: String? /// The postal code, as entered by the user. - @OptionalField(key: Personalization.FieldKeys.postalCode) + @OptionalField(key: PersonalizationInfo.FieldKeys.postalCode) public var postalCode: String? /// The user’s ISO country code. /// /// This key is only included when the system can deduce the country code. - @OptionalField(key: Personalization.FieldKeys.isoCountryCode) + @OptionalField(key: PersonalizationInfo.FieldKeys.isoCountryCode) public var isoCountryCode: String? /// The phone number, as entered by the user. - @OptionalField(key: Personalization.FieldKeys.phoneNumber) + @OptionalField(key: PersonalizationInfo.FieldKeys.phoneNumber) public var phoneNumber: String? public init() {} } -/// The migration that creates the ``Personalization`` table. -public struct CreatePersonalization: AsyncMigration { +/// The migration that creates the ``PersonalizationInfo`` table. +public struct CreatePersonalizationInfo: AsyncMigration { public func prepare(on database: any Database) async throws { - try await database.schema(Personalization.FieldKeys.schemaName) + try await database.schema(PersonalizationInfo.FieldKeys.schemaName) .field(.id, .int, .identifier(auto: true)) .field( - Personalization.FieldKeys.passID, .uuid, .required, + PersonalizationInfo.FieldKeys.passID, .uuid, .required, .references(Pass.FieldKeys.schemaName, .id, onDelete: .cascade) ) - .unique(on: Personalization.FieldKeys.passID) - .field(Personalization.FieldKeys.fullName, .string) - .field(Personalization.FieldKeys.givenName, .string) - .field(Personalization.FieldKeys.familyName, .string) - .field(Personalization.FieldKeys.emailAddress, .string) - .field(Personalization.FieldKeys.postalCode, .string) - .field(Personalization.FieldKeys.isoCountryCode, .string) - .field(Personalization.FieldKeys.phoneNumber, .string) + .unique(on: PersonalizationInfo.FieldKeys.passID) + .field(PersonalizationInfo.FieldKeys.fullName, .string) + .field(PersonalizationInfo.FieldKeys.givenName, .string) + .field(PersonalizationInfo.FieldKeys.familyName, .string) + .field(PersonalizationInfo.FieldKeys.emailAddress, .string) + .field(PersonalizationInfo.FieldKeys.postalCode, .string) + .field(PersonalizationInfo.FieldKeys.isoCountryCode, .string) + .field(PersonalizationInfo.FieldKeys.phoneNumber, .string) .create() } public func revert(on database: any Database) async throws { - try await database.schema(Personalization.FieldKeys.schemaName).delete() + try await database.schema(PersonalizationInfo.FieldKeys.schemaName).delete() } public init() {} } -extension Personalization { +extension PersonalizationInfo { enum FieldKeys { static let schemaName = "personalization_info" static let passID = FieldKey(stringLiteral: "pass_id") diff --git a/Sources/FluentWalletPasses/Models/PersonalizationModel.swift b/Sources/FluentWalletPasses/Models/PersonalizationInfoModel.swift similarity index 97% rename from Sources/FluentWalletPasses/Models/PersonalizationModel.swift rename to Sources/FluentWalletPasses/Models/PersonalizationInfoModel.swift index c478255..149ba36 100644 --- a/Sources/FluentWalletPasses/Models/PersonalizationModel.swift +++ b/Sources/FluentWalletPasses/Models/PersonalizationInfoModel.swift @@ -1,7 +1,7 @@ import FluentKit /// Represents the `Model` that stores user personalization info. -public protocol PersonalizationModel: Model where IDValue == Int { +public protocol PersonalizationInfoModel: Model where IDValue == Int { associatedtype PassType: PassModel /// The pass this personalization info is associated with. @@ -36,7 +36,7 @@ public protocol PersonalizationModel: Model where IDValue == Int { var phoneNumber: String? { get set } } -extension PersonalizationModel { +extension PersonalizationInfoModel { public var _$id: ID { guard let mirror = Mirror(reflecting: self).descendant("_id"), let id = mirror as? ID diff --git a/Tests/FluentWalletPassesTests/FluentWalletPassesTests.swift b/Tests/FluentWalletPassesTests/FluentWalletPassesTests.swift index ae16bf9..fc01b8b 100644 --- a/Tests/FluentWalletPassesTests/FluentWalletPassesTests.swift +++ b/Tests/FluentWalletPassesTests/FluentWalletPassesTests.swift @@ -72,9 +72,9 @@ struct FluentWalletPassesTests { try await migration.revert(on: test.db) } - @Test("Personalization Concrete Model") + @Test("PersonalizationInfo Concrete Model") func personalization() async throws { - let migration = CreatePersonalization() + let migration = CreatePersonalizationInfo() try await migration.prepare(on: test.db) let typeIdentifier = "Test Type Identifier" @@ -91,7 +91,7 @@ struct FluentWalletPassesTests { let isoCountryCode = "Test ISO Country Code" let phoneNumber = "Test Phone Number" - let personalization = Personalization() + let personalization = PersonalizationInfo() personalization.$pass.id = pass.id! personalization.fullName = fullName personalization.givenName = givenName @@ -104,7 +104,7 @@ struct FluentWalletPassesTests { TestOutput(personalization) ]) - let fetchedPersonalization = try #require(await Personalization.query(on: test.db).first()) + let fetchedPersonalization = try #require(await PersonalizationInfo.query(on: test.db).first()) #expect(fetchedPersonalization._$pass.id == pass.id) #expect(fetchedPersonalization._$fullName.value == fullName) #expect(fetchedPersonalization._$givenName.value == givenName)