Skip to content

Commit 72f6d45

Browse files
author
Patrick Kosterman
committed
Initial commit
1 parent 5084f98 commit 72f6d45

13 files changed

+587
-1
lines changed

README.md

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,85 @@
11
# passkit-golang-members-quickstart
2-
Quickstart to create, distribute, analyse and manage your Digital Membership for Apple Wallet and Google Pay
2+
3+
__Important Disclaimer:__ _This repository is currently under development. Below instructions are meant as a reference for beta partners, and could be subject to changes. Please note that the environment mentioned in below Quickstart is our Development Environment, which should not be used in a production setting; this is purely for exploratory testing. Data created in our Development Environment can be purged at anytime at our discretion without notice._
4+
5+
The PassKit IO SDK makes it quick and easy to create and install your branded membership passes for Apple Wallet and Google Pay.
6+
7+
8+
This repository has following structure with each purpose.
9+
- `certs` folder is a place to store your credential files.
10+
- `examples` folder contains SDK methods you can use to create membership cards and engage with members.
11+
12+
## Table of Content
13+
* [Installation](#installation)
14+
* [Prerequisites](#prerequisites)
15+
* [Quickstart](#quickstart)
16+
* [Examples](#examples)
17+
* [GUI Tool](#gui-tool)
18+
* [Documentation](#documentation)
19+
* [Check Other Passes](#check-other-passes)
20+
* [Getting Help](#getting-help)
21+
* [License](#license)
22+
23+
## Installation
24+
Install passkit-io-go with:
25+
```go
26+
go get -u github.com/PassKit/passkit-golang-sdk
27+
```
28+
Then, import SDK with:
29+
```go
30+
import(
31+
"github.com/PassKit/passkit-golang-sdk/io/members"
32+
"github.com/PassKit/passkit-golang-sdk/io"
33+
)
34+
```
35+
## Prerequisites
36+
1. Create a PassKit account. Sign up for free [HERE](https://dev-app.passkit.io/).
37+
38+
2. Download three `.pem` files you received by email after sign up.
39+
40+
To re-generate credentials, visit Settings (click gear icon in top right of the PassKit.IO web app window) > Developer Credential page and click 'Generate' (Login [HERE](https://dev-app.passkit.io/)).
41+
42+
## Quickstart
43+
By completing this Quickstart, you will be able to issue a membership card for a new member.
44+
45+
1. Get [prerequisites](#prerequisites)
46+
47+
2. Install passkit-io-go with:
48+
```go
49+
go get -u github.com/PassKit/passkit-golang-sdk
50+
```
51+
52+
3. When you created an account (Prerequisites #1), you should have received 3 files: `certificate.pem`, `key.pem` and `ca-chain.pem` by email. Please save those 3 files under `passkit-golang-members-quickstart/certs` directory. These .pem files are required to authenticate your accesss to PassKit.IO server.
53+
54+
4. Now we need to decrypt your `key.pem`. At your project root directory, run `cd ./certs openssl ec -in key.pem -out key.pem`. Your `key.pem` file should look like below.
55+
![ScreenShot](https://github.com/PassKit/passkit-golang-members-quickstart/images/decrypted_key_pem.png)
56+
If you do not see `Proc-Type: 4,ENCEYPTED` on line 2, you have successfully decrypted `key.pem`.
57+
58+
5. Replace `[email protected]` in `main.go` with your email address in order to receive the welcome email with card url which your member will also receive.
59+
60+
6. Go back to root directory with `cd ../..`. Then run `go run main.go` to create a sample program (with default template & tier) and issue a membership card against that.
61+
62+
## Examples
63+
#### Issue A Membership Card.
64+
Follow 5 steps of [Quickstart](#quickstart) to create a sample membership card and view it on your mobile.
65+
66+
#### Engage With Your Members
67+
`EngageWithMembers()` contains multiple methods you can use to engage with your members.
68+
For example, you can update contents of digital membership card or send a push notification.
69+
70+
## GUI Tool
71+
GUI tool can be accessed from [your PassKit.IO account](https://dev-app.passkit.io/login).
72+
73+
## Documentation
74+
* [PassKit.IO Membership Official Documentation](https://docs.passkit.io/protocols/member)
75+
76+
## Check Other Passes
77+
* Coupons (coming soon)
78+
* Flight Ticket (coming soon)
79+
80+
## Getting Help
81+
82+
* [Online chat support](https://passkit.com/)
83+
84+
## License
85+
Distributed under MIT License. Details available on [license file](#).

certs/StoringPEMFilesInstruction.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## Required steps for storing 3 .pem files in this ./certs directory
2+
3+
### What files do I need to store?
4+
- certificate.pem
5+
- key.pem
6+
- ca-chain.pem
7+
8+
### [IMPORTANT] How can I decrypt key.pem file?
9+
You need to decrypt key.pem with `cd ./certs openssl ec -in key.pem -out key.pem` from project root directory.
10+
11+
### Where do I need to store those 3 .pem files?
12+
Please store at passkit-golang-members-quickstart/certs directory which is the same directory as this README file.
13+
14+
### Where can I get those 3 .pem files?
15+
Those files are emailed to you right after account creation or you can find them on Settings (click gear icon in top right of the PassKit.IO web app window) > Developer Credential page (https://dev-app.passkit.io/login).
16+
17+
### Why do I need to store .pem files?
18+
.pem files are used to authenticate you to connect with PassKit server.
19+

examples/connect_passkit_sdk.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package examples
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"log"
7+
8+
"github.com/PassKit/passkit-golang-sdk/helpers/router"
9+
10+
"google.golang.org/grpc"
11+
)
12+
13+
var conn *grpc.ClientConn
14+
15+
// ConnectPasskitSdk takes your credentials and establish connection with PassKit SDK.
16+
func ConnectPasskitSdk(clientCertFile, clientKeyFile, clientCAFile, gRPCHost, gRPCPort string) {
17+
var err error
18+
19+
cert, err := ioutil.ReadFile(clientCertFile)
20+
21+
if err != nil {
22+
log.Fatalf("could not load certificate file: %v", err)
23+
}
24+
25+
key, err := ioutil.ReadFile(clientKeyFile)
26+
27+
if err != nil {
28+
log.Fatalf("could not load key file: %v", err)
29+
}
30+
31+
ca, err := ioutil.ReadFile(clientCAFile)
32+
33+
if err != nil {
34+
log.Fatalf("could not load ca file: %v", err)
35+
}
36+
37+
// Generate context object to connect to the server.
38+
if conn, err = router.NewCertAuthTLSGRPCClient(fmt.Sprintf("%s:%s", gRPCHost, gRPCPort), string(cert), string(key), string(ca)); err != nil {
39+
log.Fatal(err.Error())
40+
}
41+
42+
fmt.Println("Connect SDK Success: Established connection to the server successfully.")
43+
}

examples/count_members.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package examples
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/PassKit/passkit-golang-sdk/io"
8+
"github.com/PassKit/passkit-golang-sdk/io/members"
9+
10+
"golang.org/x/net/context"
11+
"google.golang.org/grpc/metadata"
12+
)
13+
14+
// CountMembers takes search conditions as pagination object and returns the number of members who match with the condition.
15+
func CountMembers(programId string) {
16+
fmt.Println("Counting member records match with conditions...")
17+
18+
// Generate a members module client
19+
pkMembersClient := members.NewMembersClient(conn)
20+
21+
// Generate context object to connect to the server.
22+
ctx := context.Background()
23+
ctx = metadata.NewOutgoingContext(ctx, nil)
24+
25+
listRequest := &members.ListRequest{
26+
ProgramId: programId,
27+
Pagination: &io.Pagination{
28+
FilterField: []string{"programId"},
29+
FilterValue: []string{programId},
30+
FilterOperator: []string{"eq"},
31+
},
32+
}
33+
34+
countResponse, err := pkMembersClient.CountMembers(ctx, listRequest)
35+
if err != nil {
36+
log.Fatalf("Count member err: %v\n", err)
37+
}
38+
39+
fmt.Printf("Count result was %v.\n", countResponse.Total)
40+
}

examples/create_program.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package examples
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/PassKit/passkit-golang-sdk/io"
8+
"github.com/PassKit/passkit-golang-sdk/io/members"
9+
10+
"golang.org/x/net/context"
11+
"google.golang.org/grpc/metadata"
12+
)
13+
14+
// CreateProgram takes a new program name and creates a new program. The method returns the program id.
15+
// A program needs to be created because program functions as a class object for tier and members.
16+
func CreateProgram() string {
17+
fmt.Println("Start creating a membership program...")
18+
19+
// Generate PassKit Client object for Membership protocol.
20+
pkMembersClient := members.NewMembersClient(conn)
21+
22+
// Generate context object to connect to the server.
23+
ctx := context.Background()
24+
ctx = metadata.NewOutgoingContext(ctx, nil)
25+
26+
// Create your membership program object.
27+
program := &members.Program{
28+
Name: "Membership Program",
29+
Status: []io.ProjectStatus{
30+
io.ProjectStatus_PROJECT_DRAFT,
31+
io.ProjectStatus_PROJECT_ACTIVE_FOR_OBJECT_CREATION,
32+
},
33+
}
34+
35+
// Send gRPC request to create a membership program record.
36+
programId, err := pkMembersClient.CreateProgram(ctx, program)
37+
if err != nil || programId == nil {
38+
log.Fatalf("Create program err: %v", err)
39+
}
40+
41+
// You need this program id to create Tier and Member objects in order to issue membership card.
42+
log.Printf("Create Program Success: You have successfully created your membership program. Your program id is %s.\n", programId.Id)
43+
44+
return programId.Id
45+
}

examples/create_tier.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package examples
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/PassKit/passkit-golang-sdk/io"
8+
"github.com/PassKit/passkit-golang-sdk/io/members"
9+
10+
"golang.org/x/net/context"
11+
"google.golang.org/grpc/metadata"
12+
)
13+
14+
// CreateTier takes a programId of an existing program, creates a new template (based of default template), creates a tier, and links this tier to the program.
15+
// The method returns the tier id.
16+
func CreateTier(programId string) string {
17+
fmt.Println("Start creating a membership tier...")
18+
19+
// Generate a template module client
20+
pkTemplatesClient := io.NewTemplatesClient(conn)
21+
22+
// Generate context object to connect to the server.
23+
ctx := context.Background()
24+
ctx = metadata.NewOutgoingContext(ctx, nil)
25+
26+
// In order to create a tier, we need a pass template id which holds pass design data. Let's use the default pass template for now.
27+
defaultTemplateRequest := &io.DefaultTemplateRequest{
28+
Protocol: io.PassProtocol_MEMBERSHIP,
29+
Revision: uint32(1),
30+
}
31+
32+
defaultPassTemplate, err := pkTemplatesClient.GetDefaultTemplate(ctx, defaultTemplateRequest)
33+
if err != nil {
34+
log.Fatalf("Create tier err: %v", err)
35+
}
36+
37+
// If you use the default template, you need to set name, description and timezone because these fields are mandatory.
38+
defaultPassTemplate.Name = "quick_start"
39+
defaultPassTemplate.Description = "quick start sample template"
40+
defaultPassTemplate.Timezone = "America/New_York"
41+
42+
templateId, err := pkTemplatesClient.CreateTemplate(ctx, defaultPassTemplate)
43+
if templateId == nil || err != nil {
44+
log.Fatalf("Could not create tier: %v", err)
45+
}
46+
47+
// We now have a program id which we created in create_program.go example and default pass template.
48+
// Let's create a tier. First, let's create a members module client.
49+
pkMembersClient := members.NewMembersClient(conn)
50+
51+
tier := &members.Tier{
52+
ProgramId: programId,
53+
PassTemplateId: templateId.Id,
54+
Id: "base",
55+
TierIndex: uint32(1),
56+
Name: "Base Tier",
57+
}
58+
59+
tierId, err := pkMembersClient.CreateTier(ctx, tier)
60+
if err != nil {
61+
log.Fatalf("Create tier err: %v", err)
62+
}
63+
64+
fmt.Printf("Create Tier Success: You have successfully created your tier. Your tier id is %s.\n", tierId.Id)
65+
66+
return tierId.Id
67+
}

examples/enrol_member.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package examples
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/PassKit/passkit-golang-sdk/io"
8+
"github.com/PassKit/passkit-golang-sdk/io/members"
9+
10+
"golang.org/x/net/context"
11+
"google.golang.org/grpc/metadata"
12+
)
13+
14+
// EnrolMember takes programId, tierId and memberDetails, creates a new member record, and sends a welcome email to deliver membership card url.
15+
// The method returns the member id. Member id is a part of card url.
16+
func EnrolMember(programId, tierId, emailAddress string) string {
17+
fmt.Println("Start enrolling a member...")
18+
19+
// Generate a members module client
20+
pkMembersClient := members.NewMembersClient(conn)
21+
22+
// Generate context object to connect to the server.
23+
ctx := context.Background()
24+
ctx = metadata.NewOutgoingContext(ctx, nil)
25+
26+
newMember := &members.Member{
27+
TierId: tierId,
28+
ProgramId: programId,
29+
MemberDetails: &io.Person{
30+
Surname: "Smith",
31+
Forename: "Bailey",
32+
DisplayName: "Bailey",
33+
EmailAddress: emailAddress,
34+
},
35+
}
36+
37+
memberId, err := pkMembersClient.EnrolMember(ctx, newMember)
38+
if err != nil {
39+
log.Fatalf("Create tier err: %v", err)
40+
}
41+
42+
// TODO: Change the pass url prefix to the production one
43+
fmt.Printf("Enrol Member Success: You have successfully enrolled a member. Your member id is %s.\n", memberId.Id)
44+
fmt.Printf("To check this member's membership card, please visit https://dev.pskt.io/%s\n", memberId.Id)
45+
46+
return memberId.Id
47+
}

examples/get_a_member.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package examples
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/PassKit/passkit-golang-sdk/io"
8+
"github.com/PassKit/passkit-golang-sdk/io/members"
9+
10+
"golang.org/x/net/context"
11+
"google.golang.org/grpc/metadata"
12+
)
13+
14+
// GetSingleMember takes memberId and returns the record of that member.
15+
func GetSingleMember(memberId string) {
16+
fmt.Println("Getting a member record...")
17+
18+
// Generate a members module client
19+
pkMembersClient := members.NewMembersClient(conn)
20+
21+
// Generate context object to connect to the server.
22+
ctx := context.Background()
23+
ctx = metadata.NewOutgoingContext(ctx, nil)
24+
25+
id := &io.Id{
26+
Id: memberId,
27+
}
28+
29+
memeberRecrod, err := pkMembersClient.GetMemberRecordById(ctx, id)
30+
if err != nil {
31+
log.Fatalf("Get member err: %v", err)
32+
}
33+
34+
fmt.Printf("You have successfully retrieved a member record for [%s] %v\n", memberId, *memeberRecrod)
35+
}

0 commit comments

Comments
 (0)