Skip to content
Open
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
5 changes: 0 additions & 5 deletions routePlan.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,3 @@ type RoutePlanListQueryParams struct {
type RoutePlanAddTasksParams struct {
Tasks []string `json:"tasks"`
}

type RoutePlansPaginated struct {
LastId string `json:"lastId,omitempty"`
RoutePlans []RoutePlan `json:"routePlans"`
}
50 changes: 50 additions & 0 deletions service/admin/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,53 @@ func (c *Client) Delete(adminId string) error {
)
return err
}

// Reference https://docs.onfleet.com/reference/metadata
// MetadataSet atomically adds or updates metadata fields without affecting other metadata
func (c *Client) MetadataSet(adminId string, metadata ...onfleet.Metadata) (onfleet.Admin, error) {
admin := onfleet.Admin{}
body := map[string]any{
"metadata": map[string]any{
"$set": metadata,
},
}
err := c.call(
c.apiKey,
c.rlHttpClient,
http.MethodPut,
c.url,
[]string{adminId},
nil,
body,
&admin,
)
return admin, err
}

// Reference https://docs.onfleet.com/reference/metadata
// MetadataPop atomically removes metadata fields without affecting other metadata
func (c *Client) MetadataPop(adminId string, names ...string) (onfleet.Admin, error) {
admin := onfleet.Admin{}

popArray := make([]map[string]string, len(names))
for i, name := range names {
popArray[i] = map[string]string{"name": name}
}

body := map[string]any{
"metadata": map[string]any{
"$pop": popArray,
},
}
err := c.call(
c.apiKey,
c.rlHttpClient,
http.MethodPut,
c.url,
[]string{adminId},
nil,
body,
&admin,
)
return admin, err
}
166 changes: 166 additions & 0 deletions service/admin/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,170 @@ func TestClient_ErrorScenarios(t *testing.T) {
assert.Error(t, err)
})
}
}

func TestClient_MetadataSet(t *testing.T) {
mockClient := testingutil.SetupTest(t)
defer testingutil.CleanupTest(t, mockClient)

expectedAdmin := testingutil.GetSampleAdmin()
expectedAdmin.Metadata = []onfleet.Metadata{
{
Name: "role",
Type: "string",
Value: "manager",
},
}

mockClient.AddResponse("/admins/admin_123", testingutil.MockResponse{
StatusCode: 200,
Body: expectedAdmin,
})

client := Plug("test_api_key", nil, "https://api.example.com/admins", mockClient.MockCaller)

metadata := []onfleet.Metadata{
{
Name: "role",
Type: "string",
Value: "manager",
},
}

admin, err := client.MetadataSet("admin_123", metadata...)

assert.NoError(t, err)
assert.Equal(t, expectedAdmin.ID, admin.ID)

// Verify the field was set
assert.Len(t, admin.Metadata, 1)
assert.Equal(t, "role", admin.Metadata[0].Name)
assert.Equal(t, "manager", admin.Metadata[0].Value)

mockClient.AssertRequestMade("PUT", "/admins/admin_123")
}

func TestClient_MetadataSet_Atomicity(t *testing.T) {
mockClient := testingutil.SetupTest(t)
defer testingutil.CleanupTest(t, mockClient)

expectedAdmin := testingutil.GetSampleAdmin()
expectedAdmin.Metadata = []onfleet.Metadata{
{
Name: "department",
Type: "string",
Value: "operations",
},
{
Name: "level",
Type: "number",
Value: float64(3),
},
}

mockClient.AddResponse("/admins/admin_123", testingutil.MockResponse{
StatusCode: 200,
Body: expectedAdmin,
})

client := Plug("test_api_key", nil, "https://api.example.com/admins", mockClient.MockCaller)

// Set only level field
metadata := []onfleet.Metadata{
{
Name: "level",
Type: "number",
Value: float64(3),
},
}

admin, err := client.MetadataSet("admin_123", metadata...)

assert.NoError(t, err)
assert.Equal(t, expectedAdmin.ID, admin.ID)

// Verify both fields are present (atomicity - department was preserved)
assert.Len(t, admin.Metadata, 2)

var foundDepartment, foundLevel bool
for _, m := range admin.Metadata {
if m.Name == "department" {
foundDepartment = true
assert.Equal(t, "operations", m.Value)
}
if m.Name == "level" {
foundLevel = true
assert.Equal(t, float64(3), m.Value)
}
}
assert.True(t, foundDepartment, "department field should be preserved")
assert.True(t, foundLevel, "level field should be set")

mockClient.AssertRequestMade("PUT", "/admins/admin_123")
}

func TestClient_MetadataPop(t *testing.T) {
mockClient := testingutil.SetupTest(t)
defer testingutil.CleanupTest(t, mockClient)

expectedAdmin := testingutil.GetSampleAdmin()
expectedAdmin.Metadata = []onfleet.Metadata{}

mockClient.AddResponse("/admins/admin_123", testingutil.MockResponse{
StatusCode: 200,
Body: expectedAdmin,
})

client := Plug("test_api_key", nil, "https://api.example.com/admins", mockClient.MockCaller)

admin, err := client.MetadataPop("admin_123", "temp_access")

assert.NoError(t, err)
assert.Equal(t, expectedAdmin.ID, admin.ID)

// Verify the field was removed
assert.Len(t, admin.Metadata, 0)
for _, m := range admin.Metadata {
assert.NotEqual(t, "temp_access", m.Name, "temp_access field should be removed")
}

mockClient.AssertRequestMade("PUT", "/admins/admin_123")
}

func TestClient_MetadataPop_Atomicity(t *testing.T) {
mockClient := testingutil.SetupTest(t)
defer testingutil.CleanupTest(t, mockClient)

expectedAdmin := testingutil.GetSampleAdmin()
expectedAdmin.Metadata = []onfleet.Metadata{
{
Name: "department",
Type: "string",
Value: "operations",
},
}

mockClient.AddResponse("/admins/admin_123", testingutil.MockResponse{
StatusCode: 200,
Body: expectedAdmin,
})

client := Plug("test_api_key", nil, "https://api.example.com/admins", mockClient.MockCaller)

admin, err := client.MetadataPop("admin_123", "old_field")

assert.NoError(t, err)
assert.Equal(t, expectedAdmin.ID, admin.ID)

// Verify department was preserved (atomicity)
assert.Len(t, admin.Metadata, 1)
assert.Equal(t, "department", admin.Metadata[0].Name)
assert.Equal(t, "operations", admin.Metadata[0].Value)

// Verify old_field is not present
for _, m := range admin.Metadata {
assert.NotEqual(t, "old_field", m.Name, "old_field should not be present")
}

mockClient.AssertRequestMade("PUT", "/admins/admin_123")
}
50 changes: 50 additions & 0 deletions service/destination/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,53 @@ func (c *Client) ListWithMetadataQuery(metadata []onfleet.Metadata) ([]onfleet.D
)
return destinations, err
}

// Reference https://docs.onfleet.com/reference/metadata
// MetadataSet atomically adds or updates metadata fields without affecting other metadata
func (c *Client) MetadataSet(destinationId string, metadata ...onfleet.Metadata) (onfleet.Destination, error) {
destination := onfleet.Destination{}
body := map[string]any{
"metadata": map[string]any{
"$set": metadata,
},
}
err := c.call(
c.apiKey,
c.rlHttpClient,
http.MethodPut,
c.url,
[]string{destinationId},
nil,
body,
&destination,
)
return destination, err
}

// Reference https://docs.onfleet.com/reference/metadata
// MetadataPop atomically removes metadata fields without affecting other metadata
func (c *Client) MetadataPop(destinationId string, names ...string) (onfleet.Destination, error) {
destination := onfleet.Destination{}

popArray := make([]map[string]string, len(names))
for i, name := range names {
popArray[i] = map[string]string{"name": name}
}

body := map[string]any{
"metadata": map[string]any{
"$pop": popArray,
},
}
err := c.call(
c.apiKey,
c.rlHttpClient,
http.MethodPut,
c.url,
[]string{destinationId},
nil,
body,
&destination,
)
return destination, err
}
Loading
Loading