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: 3 additions & 0 deletions cmd/client/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,7 @@ const (

API_BACKUP_LIST = "/api/backup"
API_BACKUP_DELETE = "/api/backup"

API_SETTINGS = "/api/settings"
API_SETTINGS_SYSTEM = "/api/settings/system"
)
84 changes: 84 additions & 0 deletions cmd/client/api/settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package api

import (
"fmt"
"net/http"

"github.com/mycontroller-org/server/v2/pkg/json"
settingsTY "github.com/mycontroller-org/server/v2/pkg/types/settings"
)

func (c *Client) GetSystemSettings() (*settingsTY.Settings, error) {
res, err := c.executeJson(API_SETTINGS_SYSTEM, http.MethodGet, nil, nil, nil, http.StatusOK)
if err != nil {
return nil, err
}
item := &settingsTY.Settings{}
if err := json.Unmarshal(res.Body, item); err != nil {
return nil, err
}
return item, nil
}

func (c *Client) UpdateSettings(settings *settingsTY.Settings) error {
_, err := c.executeJson(API_SETTINGS, http.MethodPost, nil, nil, settings, http.StatusOK)
return err
}

func (c *Client) SetSystemSettingsPath(keyPath, value string, rawText bool) error {
settings, err := c.GetSystemSettings()
if err != nil {
return err
}
if settings.Spec == nil {
settings.Spec = map[string]interface{}{}
}
updated := map[string]interface{}{}
if err := applyJSONPath(settings.Spec, keyPath, value, rawText, &updated); err != nil {
return err
}
settings.ID = settingsTY.KeySystemSettings
settings.Spec = updated
return c.UpdateSettings(settings)
}

func (c *Client) MergeSystemSettings(overlay map[string]interface{}) error {
if len(overlay) == 0 {
return fmt.Errorf("settings overlay is empty")
}
settings, err := c.GetSystemSettings()
if err != nil {
return err
}
if spec, ok := overlay["spec"].(map[string]interface{}); ok && overlay["id"] != nil {
overlay = spec
}
settings.ID = settingsTY.KeySystemSettings
settings.Spec = mergeSettingMaps(settings.Spec, overlay)
return c.UpdateSettings(settings)
}

func mergeSettingMaps(base, overlay map[string]interface{}) map[string]interface{} {
if base == nil {
base = map[string]interface{}{}
}
out := make(map[string]interface{}, len(base)+len(overlay))
for key, value := range base {
out[key] = value
}
for key, value := range overlay {
existing, ok := out[key]
if !ok {
out[key] = value
continue
}
existingMap, existingIsMap := existing.(map[string]interface{})
valueMap, valueIsMap := value.(map[string]interface{})
if existingIsMap && valueIsMap {
out[key] = mergeSettingMaps(existingMap, valueMap)
continue
}
out[key] = value
}
return out
}
44 changes: 44 additions & 0 deletions cmd/client/api/settings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package api

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestMergeSettingMaps(t *testing.T) {
base := map[string]interface{}{
"language": "en",
"geoLocation": map[string]interface{}{
"autoUpdate": true,
"locationName": "here",
},
}
overlay := map[string]interface{}{
"language": "de",
"geoLocation": map[string]interface{}{
"latitude": 1.5,
},
}
merged := mergeSettingMaps(base, overlay)
assert.Equal(t, "de", merged["language"])
geo := merged["geoLocation"].(map[string]interface{})
assert.Equal(t, true, geo["autoUpdate"])
assert.Equal(t, "here", geo["locationName"])
assert.Equal(t, 1.5, geo["latitude"])
}

func TestApplyJSONPathOnSettingsSpec(t *testing.T) {
spec := map[string]interface{}{
"language": "en",
"geoLocation": map[string]interface{}{
"autoUpdate": false,
},
}
out := map[string]interface{}{}
require.NoError(t, applyJSONPath(spec, "geoLocation.autoUpdate", "true", false, &out))
geo := out["geoLocation"].(map[string]interface{})
assert.Equal(t, true, geo["autoUpdate"])
assert.Equal(t, "en", out["language"])
}
37 changes: 18 additions & 19 deletions cmd/client/command/action/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ var actionCmd = &cobra.Command{
Node actions: reboot, reset, firmware-update, heartbeat, refresh-node-info
Gateway actions: discover-nodes

Node ids are quick ids: gatewayId.nodeId (for example mysensor.1).
Gateway ids are the gateway id (for example mysensor).
Reload a gateway with myc reload gateway; there is no gateway restart action.
myc action node <alias> reboot mysensor.1
myc action gateway <alias> discover-nodes mysensor
`,
SilenceUsage: true,
SilenceErrors: true,
Expand All @@ -36,27 +35,27 @@ Reload a gateway with myc reload gateway; there is no gateway restart action.
}

var nodeActionCmd = &cobra.Command{
Use: "node <action> <gateway.node> [<gateway.node>...]",
Use: "node <alias> <action> <gateway.node> [<gateway.node>...]",
Aliases: []string{"nodes"},
Short: "Send an action to one or more nodes",
Example: ` myc action node reboot mysensor.1 mysensor.2
myc action node reset mysensor.1
myc action node firmware-update mysensor.1
myc action node heartbeat mysensor.1
myc action node refresh-node-info mysensor.1`,
Args: cobra.MinimumNArgs(2),
Example: ` myc action node <alias> reboot mysensor.1 mysensor.2
myc action node <alias> reset mysensor.1
myc action node <alias> firmware-update mysensor.1
myc action node <alias> heartbeat mysensor.1
myc action node <alias> refresh-node-info mysensor.1`,
Args: cobra.MinimumNArgs(3),
SilenceUsage: true,
SilenceErrors: true,
PreRun: func(cmd *cobra.Command, args []string) {
rootCmd.UpdateStreams(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
action, err := normalizeNodeAction(args[0])
client, rest := rootCmd.TakeAlias(args)
action, err := normalizeNodeAction(rest[0])
if err != nil {
return err
}
client := rootCmd.GetClient()
ids, resolveErr := client.ResolveNodeIDs(args[1:])
ids, resolveErr := client.ResolveNodeIDs(rest[1:])
if len(ids) > 0 {
if err := client.ExecuteNodeAction(action, ids); err != nil {
return err
Expand All @@ -68,23 +67,23 @@ var nodeActionCmd = &cobra.Command{
}

var gatewayActionCmd = &cobra.Command{
Use: "gateway <action> <id> [<id>...]",
Use: "gateway <alias> <action> <id> [<id>...]",
Aliases: []string{"gw", "gateways"},
Short: "Send an action to one or more gateways",
Example: ` myc action gateway discover-nodes mysensor gw2`,
Args: cobra.MinimumNArgs(2),
Example: ` myc action gateway <alias> discover-nodes mysensor gw2`,
Args: cobra.MinimumNArgs(3),
SilenceUsage: true,
SilenceErrors: true,
PreRun: func(cmd *cobra.Command, args []string) {
rootCmd.UpdateStreams(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
action, err := normalizeGatewayAction(args[0])
client, rest := rootCmd.TakeAlias(args)
action, err := normalizeGatewayAction(rest[0])
if err != nil {
return err
}
client := rootCmd.GetClient()
ids, resolveErr := client.ResolveGatewayIDs(args[1:], true)
ids, resolveErr := client.ResolveGatewayIDs(rest[1:], true)
if len(ids) > 0 {
if err := client.ExecuteGatewayAction(action, ids); err != nil {
return err
Expand Down
Loading