Skip to content

Commit afb1d68

Browse files
committed
Update docs
1 parent 31f2e03 commit afb1d68

File tree

9 files changed

+101
-2
lines changed

9 files changed

+101
-2
lines changed

Diff for: Sources/FluentWallet/Models/Concrete Models/Device.swift

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ final public class Device: DeviceModel, @unchecked Sendable {
2424
public init() {}
2525
}
2626

27+
/// The migration that creates the ``Device`` table.
2728
public struct CreateDevice: AsyncMigration {
2829
public func prepare(on database: any Database) async throws {
2930
try await database.schema(Device.FieldKeys.schemaName)

Diff for: Sources/FluentWallet/Models/Concrete Models/LogEntry.swift

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ final public class LogEntry: LogEntryModel, @unchecked Sendable {
1919
public init() {}
2020
}
2121

22+
/// The migration that creates the ``LogEntry`` table.
2223
public struct CreateLogEntry: AsyncMigration {
2324
public func prepare(on database: any Database) async throws {
2425
try await database.schema(LogEntry.FieldKeys.schemaName)

Diff for: Sources/FluentWalletOrders/Models/Concrete Models/Order.swift

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ final public class Order: OrderModel, @unchecked Sendable {
3737
}
3838
}
3939

40+
/// The migration that creates the ``Order`` table.
4041
public struct CreateOrder: AsyncMigration {
4142
public func prepare(on database: any Database) async throws {
4243
try await database.schema(Order.FieldKeys.schemaName)

Diff for: Sources/FluentWalletOrders/Models/Concrete Models/OrdersRegistration.swift

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ final public class OrdersRegistration: OrdersRegistrationModel, @unchecked Senda
2020
public init() {}
2121
}
2222

23+
/// The migration that creates the ``OrdersRegistration`` table.
2324
public struct CreateOrdersRegistration: AsyncMigration {
2425
public func prepare(on database: any Database) async throws {
2526
try await database.schema(OrdersRegistration.FieldKeys.schemaName)

Diff for: Sources/FluentWalletPasses/FluentWalletPasses.docc/FluentWalletPasses.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,20 @@ This package provides a collection of Fluent protocol and concrete models, usefu
1313
- ``PassDataModel``
1414
- ``PassModel``
1515
- ``PassesRegistrationModel``
16-
- ``PersonalizationModel``
1716

1817
### Concrete Models
1918

2019
- ``Pass``
2120
- ``PassesRegistration``
22-
- ``Personalization``
2321

2422
### Migrations
2523

2624
- ``CreatePass``
2725
- ``CreatePassesRegistration``
26+
27+
### Personalized Passes
28+
29+
- <doc:PersonalizedPasses>
30+
- ``PersonalizationModel``
31+
- ``Personalization``
2832
- ``CreatePersonalization``
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Setting Up Pass Personalization
2+
3+
Create a personalized pass for Apple Wallet.
4+
5+
## Overview
6+
7+
> Warning: This section is a work in progress. Testing is hard without access to the certificates required to develop this feature. If you have access to the entitlements, please help us implement this feature.
8+
9+
Pass Personalization lets you create passes, referred to as personalizable passes, that prompt the user to provide personal information during signup that is used to update the pass.
10+
11+
> Important: Making a pass personalizable, just like adding NFC to a pass, requires a special entitlement issued by Apple. Although accessing such entitlements is hard if you're not a big company, you can learn more in [Getting Started with Apple Wallet](https://developer.apple.com/wallet/get-started/).
12+
13+
Personalizable passes can be distributed like any other pass. For information on personalizable passes, see the [Wallet Developer Guide](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/PassPersonalization.html#//apple_ref/doc/uid/TP40012195-CH12-SW2) and [Return a Personalized Pass](https://developer.apple.com/documentation/walletpasses/return_a_personalized_pass).
14+
15+
### Implement the Data Model
16+
17+
You'll have to make a few changes to your ``PassDataModel`` to support personalizable passes.
18+
19+
A personalizable pass is just a standard pass package with the following additional files:
20+
21+
- A `personalization.json` file.
22+
- A `[email protected]` file.
23+
24+
Implement the ``PassDataModel/personalizationJSON(on:)`` method.
25+
If the pass requires personalization, and if it was not already personalized, create the `PersonalizationJSON` struct, which will contain all the fields for the generated `personalization.json` file, and return it, otherwise return `nil`.
26+
27+
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 `[email protected]` file.
28+
29+
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.
30+
Each ``Personalization`` instance has a reference to the pass it belongs to, so you can easily retrieve the user info for the pass.
31+
32+
```swift
33+
extension PassData {
34+
func passJSON(on db: any Database) async throws -> any PassJSON.Properties {
35+
// Here create the pass JSON data as usual.
36+
try await PassJSONData(data: self, pass: self.$pass.get(on: db))
37+
}
38+
39+
func personalizationJSON(on db: any Database) async throws -> PersonalizationJSON? {
40+
let pass = try await self.$pass.get(on: db)
41+
42+
let personalization = try await Personalization.query(on: db)
43+
.filter(\.$pass.$id == pass.requireID())
44+
.first()
45+
46+
if personalization == nil {
47+
// If the pass requires personalization, create the personalization JSON struct.
48+
return PersonalizationJSON(
49+
requiredPersonalizationFields: [.name, .postalCode, .emailAddress, .phoneNumber],
50+
description: "Hello, World!"
51+
)
52+
} else {
53+
// Otherwise, return `nil`.
54+
return nil
55+
}
56+
}
57+
58+
func sourceFilesDirectoryPath(on db: any Database) async throws -> String {
59+
if self.requiresPersonalization {
60+
// If the pass requires personalization, return the URL path to the personalization template,
61+
// which must contain the `[email protected]` file.
62+
return "SourceFiles/Passes/Personalization/"
63+
} else {
64+
// Otherwise, return the URL path to the standard pass template.
65+
return "SourceFiles/Passes/Standard/"
66+
}
67+
}
68+
}
69+
```
70+
71+
### Implement the Web Service
72+
73+
After implementing the data model methods, there is nothing else you have to do.
74+
75+
Build the pass bundle with a `PassBuilder` as usual and distribute it.
76+
The user will be prompted to provide the required personal information when they add the pass.
77+
Wallet will then send the user personal information to your server, which should be saved in the ``Personalization`` table.
78+
Immediately after that, Wallet will request the updated pass.
79+
This updated pass will contain the user personalization data that was previously saved inside the ``Personalization`` table.
80+
You can access the pass linked to the personalization data by using the ``Personalization/pass`` field.
81+
82+
> 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.
83+
84+
## Topics
85+
86+
### Data Model Method
87+
88+
- ``PassDataModel/personalizationJSON(on:)``

Diff for: Sources/FluentWalletPasses/Models/Concrete Models/Pass.swift

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ final public class Pass: PassModel, @unchecked Sendable {
3535
}
3636
}
3737

38+
/// The migration that creates the ``Pass`` table.
3839
public struct CreatePass: AsyncMigration {
3940
public func prepare(on database: any Database) async throws {
4041
try await database.schema(Pass.FieldKeys.schemaName)

Diff for: Sources/FluentWalletPasses/Models/Concrete Models/PassesRegistration.swift

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ final public class PassesRegistration: PassesRegistrationModel, @unchecked Senda
2020
public init() {}
2121
}
2222

23+
/// The migration that creates the ``PassesRegistration`` table.
2324
public struct CreatePassesRegistration: AsyncMigration {
2425
public func prepare(on database: any Database) async throws {
2526
try await database.schema(PassesRegistration.FieldKeys.schemaName)

Diff for: Sources/FluentWalletPasses/Models/Concrete Models/Personalization.swift

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ final public class Personalization: PersonalizationModel, @unchecked Sendable {
5050
public init() {}
5151
}
5252

53+
/// The migration that creates the ``Personalization`` table.
5354
public struct CreatePersonalization: AsyncMigration {
5455
public func prepare(on database: any Database) async throws {
5556
try await database.schema(Personalization.FieldKeys.schemaName)

0 commit comments

Comments
 (0)