Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,8 @@ Never expose your `secretKey` in source code. Always use environment variables o
| PUT /v1/console/card-templates/{id} | `Console.UpdateTemplate()` | Y |
| GET /v1/console/card-templates/{id} | `Console.ReadTemplate()` | Y |
| GET /v1/console/card-templates/{id}/logs | `Console.EventLog()` | Y |
| GET /v1/console/pass-template-pairs | `Console.ListPassTemplatePairs()` | Y |
| GET /v1/console/card-template-pairs | `Console.ListPassTemplatePairs()` | Y |
| POST /v1/console/card-template-pairs | `Console.CreatePassTemplatePair()` | Y |
| POST /v1/console/card-templates/{id}/ios_preflight | `Console.IosPreflight()` | Y |
| GET /v1/console/ledger-items | `Console.ListLedgerItems()` | Y |
| GET /v1/console/webhooks | `Console.Webhooks.List()` | Y |
Expand Down
3 changes: 3 additions & 0 deletions accessgrid.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ type (
// ListPassTemplatePairsParams defines parameters for listing pass template pairs
ListPassTemplatePairsParams = models.ListPassTemplatePairsParams

// CreatePassTemplatePairParams defines parameters for creating a pass template pair
CreatePassTemplatePairParams = models.CreatePassTemplatePairParams

// LedgerItemPassTemplate represents a pass template reference within a ledger item's access pass
LedgerItemPassTemplate = models.LedgerItemPassTemplate

Expand Down
2 changes: 1 addition & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
const (
baseURL = "https://api.accessgrid.com"
defaultTimeout = 30 * time.Second
version = "0.2.0"
version = "0.3.0"
)

// APIError represents an error returned by the AccessGrid API
Expand Down
18 changes: 16 additions & 2 deletions models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,22 +224,26 @@ type Pagination struct {
// TemplateInfo represents minimal template info within a PassTemplatePair
type TemplateInfo struct {
ID string `json:"id"`
ExID string `json:"ex_id"`
Name string `json:"name"`
Platform string `json:"platform"`
}

// PassTemplatePair represents a paired iOS and Android template configuration
type PassTemplatePair struct {
ID string `json:"id"`
ExID string `json:"ex_id"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
IOSTemplate *TemplateInfo `json:"ios_template"`
AndroidTemplate *TemplateInfo `json:"android_template"`
}

// PassTemplatePairsResponse represents the response from listing pass template pairs
// PassTemplatePairsResponse represents the response from listing pass template pairs.
// The upstream JSON key is "card_template_pairs"; the Go field name is preserved
// for backward compatibility.
type PassTemplatePairsResponse struct {
PassTemplatePairs []PassTemplatePair `json:"pass_template_pairs"`
PassTemplatePairs []PassTemplatePair `json:"card_template_pairs"`
Pagination Pagination `json:"pagination"`
}

Expand All @@ -249,6 +253,16 @@ type ListPassTemplatePairsParams struct {
PerPage int `json:"per_page,omitempty"`
}

// CreatePassTemplatePairParams defines parameters for creating a pass template pair.
// Both referenced card templates must be published (status: ready) and use the same
// protocol. AppleCardTemplateID must reference an Apple (iOS) template and
// GoogleCardTemplateID must reference a Google (Android) template.
type CreatePassTemplatePairParams struct {
Name string `json:"name"`
AppleCardTemplateID string `json:"apple_card_template_id"`
GoogleCardTemplateID string `json:"google_card_template_id"`
}

// LedgerItemPassTemplate represents a pass template reference within a ledger item's access pass
type LedgerItemPassTemplate struct {
ID string `json:"id"`
Expand Down
14 changes: 13 additions & 1 deletion services/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (s *ConsoleService) ListPassTemplatePairs(ctx context.Context, params model
query.Add("per_page", fmt.Sprintf("%d", params.PerPage))
}

u := url.URL{Path: "/v1/console/pass-template-pairs"}
u := url.URL{Path: "/v1/console/card-template-pairs"}
if len(query) > 0 {
u.RawQuery = query.Encode()
}
Expand All @@ -212,6 +212,18 @@ func (s *ConsoleService) ListPassTemplatePairs(ctx context.Context, params model
return &response, nil
}

// CreatePassTemplatePair creates a new pass template pair linking an Apple (iOS)
// and Google (Android) card template. Both templates must be published
// (status: ready) and use the same protocol.
func (s *ConsoleService) CreatePassTemplatePair(ctx context.Context, params models.CreatePassTemplatePairParams) (*models.PassTemplatePair, error) {
var response models.PassTemplatePair
err := s.client.Request(ctx, http.MethodPost, "/v1/console/card-template-pairs", params, &response)
if err != nil {
return nil, fmt.Errorf("error creating pass template pair: %w", err)
}
return &response, nil
}

// ListLedgerItems retrieves billing ledger items
func (s *ConsoleService) ListLedgerItems(ctx context.Context, params models.ListLedgerItemsParams) (*models.LedgerItemsResponse, error) {
var response models.LedgerItemsResponse
Expand Down
63 changes: 57 additions & 6 deletions services/console_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,35 @@ func setupConsoleTestServer() (*httptest.Server, *ConsoleService) {
"timestamp": "2023-01-01T12:00:00Z"
}
]`))
case "/v1/console/pass-template-pairs":
case "/v1/console/card-template-pairs":
if r.Method == http.MethodPost {
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{
"id": "pair_new",
"ex_id": "pair_new",
"name": "New Badge Pair",
"created_at": "2026-04-15T12:00:00Z",
"ios_template": {"id": "tmpl_ios", "ex_id": "tmpl_ios", "name": "iOS Badge", "platform": "apple"},
"android_template": {"id": "tmpl_android", "ex_id": "tmpl_android", "name": "Android Badge", "platform": "android"}
}`))
return
}
w.Write([]byte(`{
"pass_template_pairs": [
"card_template_pairs": [
{
"id": "pair_1",
"ex_id": "pair_1",
"name": "Employee Badge Pair",
"created_at": "2025-01-01T00:00:00Z",
"ios_template": {"id": "tmpl_ios_1", "name": "iOS Badge", "platform": "apple"},
"android_template": {"id": "tmpl_android_1", "name": "Android Badge", "platform": "android"}
"ios_template": {"id": "tmpl_ios_1", "ex_id": "tmpl_ios_1", "name": "iOS Badge", "platform": "apple"},
"android_template": {"id": "tmpl_android_1", "ex_id": "tmpl_android_1", "name": "Android Badge", "platform": "android"}
},
{
"id": "pair_2",
"ex_id": "pair_2",
"name": "Contractor Badge Pair",
"created_at": "2025-01-02T00:00:00Z",
"ios_template": {"id": "tmpl_ios_2", "name": "iOS Contractor", "platform": "apple"},
"ios_template": {"id": "tmpl_ios_2", "ex_id": "tmpl_ios_2", "name": "iOS Contractor", "platform": "apple"},
"android_template": null
}
],
Expand Down Expand Up @@ -381,7 +395,7 @@ func TestConsoleService_ListPassTemplatePairs_WithPagination(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
capturedURL = r.URL.String()
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"pass_template_pairs": [], "pagination": {"current_page": 2, "total_pages": 5}}`))
w.Write([]byte(`{"card_template_pairs": [], "pagination": {"current_page": 2, "total_pages": 5}}`))
}))
defer server.Close()

Expand Down Expand Up @@ -413,6 +427,43 @@ func TestConsoleService_ListPassTemplatePairs_WithPagination(t *testing.T) {
if !strings.Contains(capturedURL, "per_page=10") {
t.Errorf("expected per_page=10 in URL, got %s", capturedURL)
}
if !strings.Contains(capturedURL, "/v1/console/card-template-pairs") {
t.Errorf("expected path /v1/console/card-template-pairs, got %s", capturedURL)
}
}

func TestConsoleService_CreatePassTemplatePair(t *testing.T) {
server, service := setupConsoleTestServer()
defer server.Close()

ctx := context.Background()
pair, err := service.CreatePassTemplatePair(ctx, models.CreatePassTemplatePairParams{
Name: "New Badge Pair",
AppleCardTemplateID: "tmpl_ios",
GoogleCardTemplateID: "tmpl_android",
})
if err != nil {
t.Fatalf("CreatePassTemplatePair() error = %v", err)
}

if pair.ID != "pair_new" {
t.Errorf("pair.ID = %v, want pair_new", pair.ID)
}
if pair.ExID != "pair_new" {
t.Errorf("pair.ExID = %v, want pair_new", pair.ExID)
}
if pair.Name != "New Badge Pair" {
t.Errorf("pair.Name = %v, want New Badge Pair", pair.Name)
}
if pair.IOSTemplate == nil || pair.IOSTemplate.Platform != "apple" {
t.Errorf("pair.IOSTemplate = %+v, want apple platform", pair.IOSTemplate)
}
if pair.AndroidTemplate == nil || pair.AndroidTemplate.Platform != "android" {
t.Errorf("pair.AndroidTemplate = %+v, want android platform", pair.AndroidTemplate)
}
if pair.IOSTemplate.ExID != "tmpl_ios" {
t.Errorf("pair.IOSTemplate.ExID = %v, want tmpl_ios", pair.IOSTemplate.ExID)
}
}

// --- Ledger Items ---
Expand Down
Loading