Skip to content

Commit 06db2ef

Browse files
NitriKxclaude
andcommitted
feat(admin): add Triggers API for webhook notification management
Adds typed bindings for the Cloudinary /triggers endpoint: ListTriggers, GetTrigger, CreateTrigger, UpdateTrigger, DeleteTrigger. Supports filter (JSONLogic), payload_template (Mustache), auth_scheme, and additive flag. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d785f74 commit 06db2ef

2 files changed

Lines changed: 228 additions & 0 deletions

File tree

api/admin/triggers.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package admin
2+
3+
// Enables you to manage webhook notification triggers for your Cloudinary product environment.
4+
//
5+
// https://cloudinary.com/documentation/notifications
6+
7+
import (
8+
"context"
9+
10+
"github.com/cloudinary/cloudinary-go/v2/api"
11+
)
12+
13+
const (
14+
triggersEndpoint api.EndPoint = "triggers"
15+
)
16+
17+
// Trigger represents a single webhook notification trigger.
18+
type Trigger struct {
19+
ID string `json:"id,omitempty"`
20+
URI string `json:"uri,omitempty"`
21+
EventType string `json:"event_type,omitempty"`
22+
Additive bool `json:"additive"`
23+
Filter map[string]any `json:"filter,omitempty"`
24+
FilterLanguage string `json:"filter_language,omitempty"`
25+
PayloadTemplate map[string]any `json:"payload_template,omitempty"`
26+
AuthScheme string `json:"auth_scheme,omitempty"`
27+
ProductEnvironmentID string `json:"product_environment_id,omitempty"`
28+
URIType string `json:"uri_type,omitempty"`
29+
CreatedAt string `json:"created_at,omitempty"`
30+
UpdatedAt string `json:"updated_at,omitempty"`
31+
}
32+
33+
// ListTriggersParams are the parameters for ListTriggers.
34+
type ListTriggersParams struct{}
35+
36+
// ListTriggersResult is the result of ListTriggers.
37+
type ListTriggersResult struct {
38+
Triggers []Trigger `json:"triggers"`
39+
Error api.ErrorResp `json:"error,omitempty"`
40+
}
41+
42+
// ListTriggers lists all webhook notification triggers for the product environment.
43+
func (a *API) ListTriggers(ctx context.Context, params ListTriggersParams) (*ListTriggersResult, error) {
44+
res := &ListTriggersResult{}
45+
_, err := a.get(ctx, triggersEndpoint, params, res)
46+
return res, err
47+
}
48+
49+
// GetTriggerParams are the parameters for GetTrigger.
50+
type GetTriggerParams struct {
51+
TriggerID string `json:"-"`
52+
}
53+
54+
// GetTriggerResult is the result of GetTrigger.
55+
type GetTriggerResult struct {
56+
Trigger
57+
Error api.ErrorResp `json:"error,omitempty"`
58+
}
59+
60+
// GetTrigger retrieves a single webhook notification trigger by its ID.
61+
// Cloudinary does not expose a single-resource GET endpoint, so this is
62+
// implemented as ListTriggers filtered to the matching ID.
63+
func (a *API) GetTrigger(ctx context.Context, params GetTriggerParams) (*GetTriggerResult, error) {
64+
list, err := a.ListTriggers(ctx, ListTriggersParams{})
65+
if err != nil {
66+
return nil, err
67+
}
68+
if list.Error.Message != "" {
69+
return &GetTriggerResult{Error: list.Error}, nil
70+
}
71+
for _, t := range list.Triggers {
72+
if t.ID == params.TriggerID {
73+
return &GetTriggerResult{Trigger: t}, nil
74+
}
75+
}
76+
// Not found — return empty result with no error; caller checks ID == "".
77+
return &GetTriggerResult{}, nil
78+
}
79+
80+
// CreateTriggerParams are the parameters for CreateTrigger.
81+
type CreateTriggerParams struct {
82+
URI string `json:"uri"`
83+
EventType string `json:"event_type"`
84+
Additive bool `json:"additive,omitempty"`
85+
Filter map[string]any `json:"filter,omitempty"`
86+
FilterLanguage string `json:"filter_language,omitempty"`
87+
PayloadTemplate map[string]any `json:"payload_template,omitempty"`
88+
AuthScheme string `json:"auth_scheme,omitempty"`
89+
}
90+
91+
// CreateTriggerResult is the result of CreateTrigger.
92+
type CreateTriggerResult struct {
93+
Trigger
94+
Error api.ErrorResp `json:"error,omitempty"`
95+
}
96+
97+
// CreateTrigger creates a new webhook notification trigger.
98+
func (a *API) CreateTrigger(ctx context.Context, params CreateTriggerParams) (*CreateTriggerResult, error) {
99+
res := &CreateTriggerResult{}
100+
_, err := a.post(ctx, triggersEndpoint, params, res)
101+
return res, err
102+
}
103+
104+
// UpdateTriggerParams are the parameters for UpdateTrigger.
105+
type UpdateTriggerParams struct {
106+
TriggerID string `json:"-"`
107+
URI string `json:"uri,omitempty"`
108+
EventType string `json:"event_type,omitempty"`
109+
Additive *bool `json:"additive,omitempty"`
110+
Filter map[string]any `json:"filter,omitempty"`
111+
FilterLanguage string `json:"filter_language,omitempty"`
112+
PayloadTemplate map[string]any `json:"payload_template,omitempty"`
113+
AuthScheme string `json:"auth_scheme,omitempty"`
114+
}
115+
116+
// UpdateTriggerResult is the result of UpdateTrigger.
117+
type UpdateTriggerResult struct {
118+
Trigger
119+
Error api.ErrorResp `json:"error,omitempty"`
120+
}
121+
122+
// UpdateTrigger updates an existing webhook notification trigger.
123+
func (a *API) UpdateTrigger(ctx context.Context, params UpdateTriggerParams) (*UpdateTriggerResult, error) {
124+
res := &UpdateTriggerResult{}
125+
_, err := a.put(ctx, api.BuildPath(triggersEndpoint, params.TriggerID), params, res)
126+
return res, err
127+
}
128+
129+
// DeleteTriggerParams are the parameters for DeleteTrigger.
130+
type DeleteTriggerParams struct {
131+
TriggerID string `json:"-"`
132+
}
133+
134+
// DeleteTriggerResult is the result of DeleteTrigger.
135+
type DeleteTriggerResult struct {
136+
Message string `json:"message,omitempty"`
137+
Error api.ErrorResp `json:"error,omitempty"`
138+
}
139+
140+
// DeleteTrigger deletes a webhook notification trigger by its ID.
141+
func (a *API) DeleteTrigger(ctx context.Context, params DeleteTriggerParams) (*DeleteTriggerResult, error) {
142+
res := &DeleteTriggerResult{}
143+
_, err := a.delete(ctx, api.BuildPath(triggersEndpoint, params.TriggerID), params, res)
144+
return res, err
145+
}

api/admin/triggers_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package admin_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/cloudinary/cloudinary-go/v2/api/admin"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
const testTriggerURI = "https://example.com/000-go-trigger-test"
11+
12+
var testTriggerID string
13+
14+
func TestTriggers_CreateTrigger(t *testing.T) {
15+
resp, err := adminAPI.CreateTrigger(ctx, admin.CreateTriggerParams{
16+
URI: testTriggerURI,
17+
EventType: "upload",
18+
})
19+
20+
if err != nil || resp.Error.Message != "" {
21+
t.Error(resp, err)
22+
return
23+
}
24+
25+
testTriggerID = resp.ID
26+
assert.NotEmpty(t, testTriggerID)
27+
}
28+
29+
func TestTriggers_ListTriggers(t *testing.T) {
30+
resp, err := adminAPI.ListTriggers(ctx, admin.ListTriggersParams{})
31+
32+
if err != nil || resp.Error.Message != "" {
33+
t.Error(resp, err)
34+
}
35+
}
36+
37+
func TestTriggers_GetTrigger(t *testing.T) {
38+
if testTriggerID == "" {
39+
t.Skip("create trigger test did not run or failed")
40+
}
41+
42+
resp, err := adminAPI.GetTrigger(ctx, admin.GetTriggerParams{
43+
TriggerID: testTriggerID,
44+
})
45+
46+
if err != nil || resp.Error.Message != "" {
47+
t.Error(resp, err)
48+
return
49+
}
50+
51+
assert.Equal(t, testTriggerID, resp.ID)
52+
}
53+
54+
func TestTriggers_UpdateTrigger(t *testing.T) {
55+
if testTriggerID == "" {
56+
t.Skip("create trigger test did not run or failed")
57+
}
58+
59+
resp, err := adminAPI.UpdateTrigger(ctx, admin.UpdateTriggerParams{
60+
TriggerID: testTriggerID,
61+
URI: testTriggerURI,
62+
EventType: "upload",
63+
AuthScheme: "default",
64+
})
65+
66+
if err != nil || resp.Error.Message != "" {
67+
t.Error(resp, err)
68+
}
69+
}
70+
71+
func TestTriggers_DeleteTrigger(t *testing.T) {
72+
if testTriggerID == "" {
73+
t.Skip("create trigger test did not run or failed")
74+
}
75+
76+
resp, err := adminAPI.DeleteTrigger(ctx, admin.DeleteTriggerParams{
77+
TriggerID: testTriggerID,
78+
})
79+
80+
if err != nil || resp.Error.Message != "" {
81+
t.Error(resp, err)
82+
}
83+
}

0 commit comments

Comments
 (0)