Skip to content

Commit cc557c7

Browse files
authored
Merge pull request #1 from didww/voice_in_trunk_voice_in_trunk_group
Add voice_in_trunk and voice_in_trunk_group relationships to DID
2 parents a71e4af + 0be5c95 commit cc557c7

7 files changed

Lines changed: 314 additions & 0 deletions

File tree

dids_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package didww
22

33
import (
44
"context"
5+
"io"
56
"net/http"
67
"testing"
78
)
@@ -122,3 +123,111 @@ func TestDIDsUpdateRequiresID(t *testing.T) {
122123
t.Fatal("expected error when updating without ID")
123124
}
124125
}
126+
127+
func TestDIDsUpdateAssignTrunk(t *testing.T) {
128+
var capturedBody []byte
129+
server := newTestServerWithInspector(t, map[string]testRoute{
130+
"PATCH /v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b": {status: http.StatusOK, fixture: "dids/show_with_trunk.json"},
131+
}, func(r *http.Request) {
132+
capturedBody, _ = io.ReadAll(r.Body)
133+
})
134+
135+
did, err := server.client.DIDs().Update(context.Background(), &DID{
136+
ID: "9df99644-f1a5-4a3c-99a4-559d758eb96b",
137+
VoiceInTrunkID: "41b94706-325e-4704-a433-d65105758836",
138+
})
139+
if err != nil {
140+
t.Fatalf("unexpected error: %v", err)
141+
}
142+
143+
assertRequestJSON(t, capturedBody, "dids/update_assign_trunk_request.json")
144+
145+
if did.VoiceInTrunk == nil {
146+
t.Fatal("expected non-nil VoiceInTrunk")
147+
}
148+
if did.VoiceInTrunk.ID != "41b94706-325e-4704-a433-d65105758836" {
149+
t.Errorf("expected VoiceInTrunk ID '41b94706-325e-4704-a433-d65105758836', got %q", did.VoiceInTrunk.ID)
150+
}
151+
if did.VoiceInTrunk.Name != "hello, test pstn trunk" {
152+
t.Errorf("expected VoiceInTrunk Name 'hello, test pstn trunk', got %q", did.VoiceInTrunk.Name)
153+
}
154+
}
155+
156+
func TestDIDsUpdateAssignTrunkGroup(t *testing.T) {
157+
var capturedBody []byte
158+
server := newTestServerWithInspector(t, map[string]testRoute{
159+
"PATCH /v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b": {status: http.StatusOK, fixture: "dids/show_with_trunk_group.json"},
160+
}, func(r *http.Request) {
161+
capturedBody, _ = io.ReadAll(r.Body)
162+
})
163+
164+
did, err := server.client.DIDs().Update(context.Background(), &DID{
165+
ID: "9df99644-f1a5-4a3c-99a4-559d758eb96b",
166+
VoiceInTrunkGroupID: "b2319703-ce6c-480d-bb53-614e7abcfc96",
167+
})
168+
if err != nil {
169+
t.Fatalf("unexpected error: %v", err)
170+
}
171+
172+
assertRequestJSON(t, capturedBody, "dids/update_assign_trunk_group_request.json")
173+
174+
if did.VoiceInTrunkGroup == nil {
175+
t.Fatal("expected non-nil VoiceInTrunkGroup")
176+
}
177+
if did.VoiceInTrunkGroup.ID != "b2319703-ce6c-480d-bb53-614e7abcfc96" {
178+
t.Errorf("expected VoiceInTrunkGroup ID 'b2319703-ce6c-480d-bb53-614e7abcfc96', got %q", did.VoiceInTrunkGroup.ID)
179+
}
180+
if did.VoiceInTrunkGroup.Name != "trunk group sample with 2 trunks" {
181+
t.Errorf("expected VoiceInTrunkGroup Name 'trunk group sample with 2 trunks', got %q", did.VoiceInTrunkGroup.Name)
182+
}
183+
}
184+
185+
func TestDIDsFindWithTrunkResolved(t *testing.T) {
186+
_, client := newTestServer(t, map[string]testRoute{
187+
"GET /v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b": {status: http.StatusOK, fixture: "dids/show_with_trunk.json"},
188+
})
189+
190+
params := NewQueryParams().Include("voice_in_trunk")
191+
did, err := client.DIDs().Find(context.Background(), "9df99644-f1a5-4a3c-99a4-559d758eb96b", params)
192+
if err != nil {
193+
t.Fatalf("unexpected error: %v", err)
194+
}
195+
196+
if did.VoiceInTrunk == nil {
197+
t.Fatal("expected non-nil VoiceInTrunk")
198+
}
199+
if did.VoiceInTrunk.ID != "41b94706-325e-4704-a433-d65105758836" {
200+
t.Errorf("expected VoiceInTrunk ID '41b94706-325e-4704-a433-d65105758836', got %q", did.VoiceInTrunk.ID)
201+
}
202+
if did.VoiceInTrunk.Name != "hello, test pstn trunk" {
203+
t.Errorf("expected VoiceInTrunk Name 'hello, test pstn trunk', got %q", did.VoiceInTrunk.Name)
204+
}
205+
if did.VoiceInTrunkGroup != nil {
206+
t.Error("expected nil VoiceInTrunkGroup (mutual exclusivity)")
207+
}
208+
}
209+
210+
func TestDIDsFindWithTrunkGroupResolved(t *testing.T) {
211+
_, client := newTestServer(t, map[string]testRoute{
212+
"GET /v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b": {status: http.StatusOK, fixture: "dids/show_with_trunk_group.json"},
213+
})
214+
215+
params := NewQueryParams().Include("voice_in_trunk_group")
216+
did, err := client.DIDs().Find(context.Background(), "9df99644-f1a5-4a3c-99a4-559d758eb96b", params)
217+
if err != nil {
218+
t.Fatalf("unexpected error: %v", err)
219+
}
220+
221+
if did.VoiceInTrunkGroup == nil {
222+
t.Fatal("expected non-nil VoiceInTrunkGroup")
223+
}
224+
if did.VoiceInTrunkGroup.ID != "b2319703-ce6c-480d-bb53-614e7abcfc96" {
225+
t.Errorf("expected VoiceInTrunkGroup ID 'b2319703-ce6c-480d-bb53-614e7abcfc96', got %q", did.VoiceInTrunkGroup.ID)
226+
}
227+
if did.VoiceInTrunkGroup.Name != "trunk group sample with 2 trunks" {
228+
t.Errorf("expected VoiceInTrunkGroup Name 'trunk group sample with 2 trunks', got %q", did.VoiceInTrunkGroup.Name)
229+
}
230+
if did.VoiceInTrunk != nil {
231+
t.Error("expected nil VoiceInTrunk (mutual exclusivity)")
232+
}
233+
}

jsonapi/jsonapi.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ func ToOneRelationship(ref RelationshipRef) map[string]any {
5252
return map[string]any{"data": ref}
5353
}
5454

55+
// NullRelationship builds a null to-one relationship entry ({"data": null}).
56+
func NullRelationship() map[string]any {
57+
return map[string]any{"data": nil}
58+
}
59+
5560
// ToManyRelationship builds a to-many relationship entry.
5661
func ToManyRelationship(refs []RelationshipRef) map[string]any {
5762
return map[string]any{"data": refs}

resources.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,28 @@ type DID struct {
257257
ExpiresAt string `json:"expires_at" api:"readonly"`
258258
ChannelsIncludedCount int `json:"channels_included_count" api:"readonly"`
259259
DedicatedChannelsCount int `json:"dedicated_channels_count"`
260+
// Relationship IDs for create/update
261+
VoiceInTrunkID string `json:"-" rel:"voice_in_trunk,voice_in_trunks"`
262+
VoiceInTrunkGroupID string `json:"-" rel:"voice_in_trunk_group,voice_in_trunk_groups"`
260263
// Resolved relationships
261264
Order *Order `json:"-" rel:"order"`
262265
AddressVerification *AddressVerification `json:"-" rel:"address_verification"`
263266
DIDGroup *DIDGroup `json:"-" rel:"did_group"`
267+
VoiceInTrunk *VoiceInTrunk `json:"-" rel:"voice_in_trunk"`
268+
VoiceInTrunkGroup *VoiceInTrunkGroup `json:"-" rel:"voice_in_trunk_group"`
269+
}
270+
271+
// MarshalRelationships implements RelationshipMarshaler for DID.
272+
// Ensures mutual exclusivity: setting a trunk nullifies the trunk group and vice versa.
273+
func (d *DID) MarshalRelationships() (map[string]any, error) {
274+
rels := make(map[string]any)
275+
if d.VoiceInTrunkID != "" {
276+
rels["voice_in_trunk_group"] = jsonapi.NullRelationship()
277+
}
278+
if d.VoiceInTrunkGroupID != "" {
279+
rels["voice_in_trunk"] = jsonapi.NullRelationship()
280+
}
281+
return rels, nil
264282
}
265283

266284
// OrderItemAttributes contains the attributes of an order item.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"data": {
3+
"id": "9df99644-f1a5-4a3c-99a4-559d758eb96b",
4+
"type": "dids",
5+
"attributes": {
6+
"blocked": false,
7+
"capacity_limit": 2,
8+
"description": "something",
9+
"terminated": false,
10+
"awaiting_registration": false,
11+
"created_at": "2018-12-27T09:59:55.015Z",
12+
"number": "16091609123456797",
13+
"expires_at": "2019-11-27T10:00:04.755Z",
14+
"channels_included_count": 0,
15+
"billing_cycles_count": null,
16+
"dedicated_channels_count": 0
17+
},
18+
"relationships": {
19+
"did_group": {
20+
"links": {
21+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/did_group",
22+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/did_group"
23+
}
24+
},
25+
"order": {
26+
"links": {
27+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/order",
28+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/order"
29+
}
30+
},
31+
"voice_in_trunk": {
32+
"links": {
33+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/voice_in_trunk",
34+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/voice_in_trunk"
35+
},
36+
"data": {
37+
"type": "voice_in_trunks",
38+
"id": "41b94706-325e-4704-a433-d65105758836"
39+
}
40+
},
41+
"voice_in_trunk_group": {
42+
"links": {
43+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/voice_in_trunk_group",
44+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/voice_in_trunk_group"
45+
},
46+
"data": null
47+
},
48+
"capacity_pool": {
49+
"links": {
50+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/capacity_pool",
51+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/capacity_pool"
52+
}
53+
},
54+
"shared_capacity_group": {
55+
"links": {
56+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/shared_capacity_group",
57+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/shared_capacity_group"
58+
}
59+
}
60+
}
61+
},
62+
"included": [
63+
{
64+
"id": "41b94706-325e-4704-a433-d65105758836",
65+
"type": "voice_in_trunks",
66+
"attributes": {
67+
"priority": 1,
68+
"capacity_limit": null,
69+
"weight": 65535,
70+
"name": "hello, test pstn trunk",
71+
"cli_format": "e164",
72+
"cli_prefix": null,
73+
"description": null,
74+
"ringing_timeout": null,
75+
"configuration": {
76+
"type": "pstn_configurations",
77+
"attributes": {
78+
"dst": "558540420024"
79+
}
80+
},
81+
"created_at": "2018-12-29T09:51:54.661Z"
82+
},
83+
"relationships": {
84+
"voice_in_trunk_group": {
85+
"links": {
86+
"self": "https://sandbox-api.didww.com/v3/voice_in_trunks/41b94706-325e-4704-a433-d65105758836/relationships/voice_in_trunk_group",
87+
"related": "https://sandbox-api.didww.com/v3/voice_in_trunks/41b94706-325e-4704-a433-d65105758836/voice_in_trunk_group"
88+
}
89+
},
90+
"pop": {
91+
"links": {
92+
"self": "https://sandbox-api.didww.com/v3/voice_in_trunks/41b94706-325e-4704-a433-d65105758836/relationships/pop",
93+
"related": "https://sandbox-api.didww.com/v3/voice_in_trunks/41b94706-325e-4704-a433-d65105758836/pop"
94+
}
95+
}
96+
}
97+
}
98+
]
99+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"data": {
3+
"id": "9df99644-f1a5-4a3c-99a4-559d758eb96b",
4+
"type": "dids",
5+
"attributes": {
6+
"blocked": false,
7+
"capacity_limit": 2,
8+
"description": "something",
9+
"terminated": false,
10+
"awaiting_registration": false,
11+
"created_at": "2018-12-27T09:59:55.015Z",
12+
"number": "16091609123456797",
13+
"expires_at": "2019-11-27T10:00:04.755Z",
14+
"channels_included_count": 0,
15+
"billing_cycles_count": null,
16+
"dedicated_channels_count": 0
17+
},
18+
"relationships": {
19+
"did_group": {
20+
"links": {
21+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/did_group",
22+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/did_group"
23+
}
24+
},
25+
"order": {
26+
"links": {
27+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/order",
28+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/order"
29+
}
30+
},
31+
"voice_in_trunk": {
32+
"links": {
33+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/voice_in_trunk",
34+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/voice_in_trunk"
35+
},
36+
"data": null
37+
},
38+
"voice_in_trunk_group": {
39+
"links": {
40+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/voice_in_trunk_group",
41+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/voice_in_trunk_group"
42+
},
43+
"data": {
44+
"type": "voice_in_trunk_groups",
45+
"id": "b2319703-ce6c-480d-bb53-614e7abcfc96"
46+
}
47+
},
48+
"capacity_pool": {
49+
"links": {
50+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/capacity_pool",
51+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/capacity_pool"
52+
}
53+
},
54+
"shared_capacity_group": {
55+
"links": {
56+
"self": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/relationships/shared_capacity_group",
57+
"related": "https://sandbox-api.didww.com/v3/dids/9df99644-f1a5-4a3c-99a4-559d758eb96b/shared_capacity_group"
58+
}
59+
}
60+
}
61+
},
62+
"included": [
63+
{
64+
"id": "b2319703-ce6c-480d-bb53-614e7abcfc96",
65+
"type": "voice_in_trunk_groups",
66+
"attributes": {
67+
"created_at": "2018-12-28T11:07:28.007Z",
68+
"name": "trunk group sample with 2 trunks",
69+
"capacity_limit": 1000
70+
},
71+
"relationships": {
72+
"voice_in_trunks": {
73+
"links": {
74+
"self": "https://sandbox-api.didww.com/v3/voice_in_trunk_groups/b2319703-ce6c-480d-bb53-614e7abcfc96/relationships/voice_in_trunks",
75+
"related": "https://sandbox-api.didww.com/v3/voice_in_trunk_groups/b2319703-ce6c-480d-bb53-614e7abcfc96/voice_in_trunks"
76+
}
77+
}
78+
}
79+
}
80+
]
81+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"data":{"id":"9df99644-f1a5-4a3c-99a4-559d758eb96b","type":"dids","attributes":{"capacity_limit":null,"dedicated_channels_count":0,"description":null},"relationships":{"voice_in_trunk":{"data":null},"voice_in_trunk_group":{"data":{"type":"voice_in_trunk_groups","id":"b2319703-ce6c-480d-bb53-614e7abcfc96"}}}}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"data":{"id":"9df99644-f1a5-4a3c-99a4-559d758eb96b","type":"dids","attributes":{"capacity_limit":null,"dedicated_channels_count":0,"description":null},"relationships":{"voice_in_trunk":{"data":{"type":"voice_in_trunks","id":"41b94706-325e-4704-a433-d65105758836"}},"voice_in_trunk_group":{"data":null}}}}

0 commit comments

Comments
 (0)