Skip to content

Commit

Permalink
fix(profile): Using config set profile.something calls SaveProfile.
Browse files Browse the repository at this point in the history
Merge pull request #500 from qri-io/set-profile-peername
  • Loading branch information
dustmop authored Jul 25, 2018
2 parents 30fd504 + a1a464c commit 1b13e0e
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 40 deletions.
17 changes: 17 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/spf13/cobra"
)

const profilePrefix = "profile."

// NewConfigCommand creates a new `qri config` cobra command
// config represents commands that read & modify configuration settings
func NewConfigCommand(f Factory, ioStreams IOStreams) *cobra.Command {
Expand Down Expand Up @@ -135,6 +137,9 @@ func (o *ConfigOptions) Set(args []string) (err error) {
"profile.thumb": true,
}

profile := lib.Config.Profile
profileChanged := false

for i := 0; i < len(args)-1; i = i + 2 {
var value interface{}
path := strings.ToLower(args[i])
Expand All @@ -146,6 +151,12 @@ func (o *ConfigOptions) Set(args []string) (err error) {
if err = setPhotoPath(o.ProfileRequests, path, args[i+1]); err != nil {
return err
}
} else if strings.HasPrefix(path, profilePrefix) {
field := strings.ToLower(path[len(profilePrefix):])
if err = profile.SetField(field, args[i+1]); err != nil {
return err
}
profileChanged = true
} else {
if err = yaml.Unmarshal([]byte(args[i+1]), &value); err != nil {
return err
Expand All @@ -159,6 +170,12 @@ func (o *ConfigOptions) Set(args []string) (err error) {
if err = lib.SetConfig(lib.Config); err != nil {
return err
}
if profileChanged {
var res config.ProfilePod
if err = o.ProfileRequests.SaveProfile(profile, &res); err != nil {
return err
}
}

printSuccess(o.Out, "config updated")
return nil
Expand Down
15 changes: 7 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,13 @@ func (cfg Config) path(path string) (elem reflect.Value, err error) {
// ImmutablePaths returns a map of paths that should never be modified
func ImmutablePaths() map[string]bool {
return map[string]bool{
"p2p.peerid": true,
"p2p.pubkey": true,
"p2p.privkey": true,
"profile.id": true,
"profile.privkey": true,
"profile.peername": true,
"profile.created": true,
"profile.updated": true,
"p2p.peerid": true,
"p2p.pubkey": true,
"p2p.privkey": true,
"profile.id": true,
"profile.privkey": true,
"profile.created": true,
"profile.updated": true,
}
}

Expand Down
82 changes: 61 additions & 21 deletions config/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"crypto/rand"
"encoding/base64"
"fmt"
"time"

"github.com/libp2p/go-libp2p-crypto"
Expand Down Expand Up @@ -82,7 +83,7 @@ func DefaultProfile() *ProfilePod {
}

// Validate validates all fields of profile returning all errors found.
func (cfg ProfilePod) Validate() error {
func (p ProfilePod) Validate() error {
schema := jsonschema.Must(`{
"$schema": "http://json-schema.org/draft-06/schema#",
"title": "Profile",
Expand Down Expand Up @@ -213,32 +214,71 @@ func (cfg ProfilePod) Validate() error {
"privkey"
]
}`)
return validate(schema, &cfg)
return validate(schema, &p)
}

// Copy makes a deep copy of the ProfilePod struct
func (cfg *ProfilePod) Copy() *ProfilePod {
func (p *ProfilePod) Copy() *ProfilePod {
res := &ProfilePod{
ID: cfg.ID,
PrivKey: cfg.PrivKey,
Peername: cfg.Peername,
Created: cfg.Created,
Updated: cfg.Updated,
Type: cfg.Type,
Email: cfg.Email,
Name: cfg.Name,
Description: cfg.Description,
HomeURL: cfg.HomeURL,
Color: cfg.Color,
Thumb: cfg.Thumb,
Photo: cfg.Photo,
Poster: cfg.Poster,
Twitter: cfg.Twitter,
ID: p.ID,
PrivKey: p.PrivKey,
Peername: p.Peername,
Created: p.Created,
Updated: p.Updated,
Type: p.Type,
Email: p.Email,
Name: p.Name,
Description: p.Description,
HomeURL: p.HomeURL,
Color: p.Color,
Thumb: p.Thumb,
Photo: p.Photo,
Poster: p.Poster,
Twitter: p.Twitter,
}
if cfg.PeerIDs != nil {
res.PeerIDs = make([]string, len(cfg.PeerIDs))
copy(res.PeerIDs, cfg.PeerIDs)
if p.PeerIDs != nil {
res.PeerIDs = make([]string, len(p.PeerIDs))
copy(res.PeerIDs, p.PeerIDs)
}

return res
}

// SetField assigns to the name field of the Profile.
// TODO: Replace this with a generic package.
func (p *ProfilePod) SetField(field, value string) error {
if field == "id" {
p.ID = value
} else if field == "privkey" {
return fmt.Errorf("Cannot set profile.privkey, read-only")
} else if field == "peername" {
p.Peername = value
} else if field == "created" {
return fmt.Errorf("Cannot set profile.created, read-only")
} else if field == "updated" {
return fmt.Errorf("Cannot set profile.updated, read-only")
} else if field == "type" {
p.Type = value
} else if field == "email" {
p.Email = value
} else if field == "name" {
p.Name = value
} else if field == "description" {
p.Description = value
} else if field == "homeurl" {
p.HomeURL = value
} else if field == "color" {
p.Color = value
} else if field == "thumb" {
p.Thumb = value
} else if field == "photo" {
return fmt.Errorf("Not implemented: set profile.photo")
} else if field == "poster" {
p.Poster = value
} else if field == "twitter" {
p.Twitter = value
} else {
return fmt.Errorf("Unknown profile field: %s", value)
}
return nil
}
74 changes: 63 additions & 11 deletions config/profile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"reflect"
"testing"
"time"
)

func TestProfileValidate(t *testing.T) {
Expand All @@ -13,26 +14,77 @@ func TestProfileValidate(t *testing.T) {
}

func TestProfileCopy(t *testing.T) {
// build off DefaultProfile so we can test that the profile Copy
// actually copies over correctly (ie, deeply)
p := DefaultProfile()
p.PeerIDs = []string{"1", "2", "3"}

cases := []struct {
profile *ProfilePod
}{
{p},
{&ProfilePod{Type: "peer"}},
{&ProfilePod{Name: "user", Color: "blue"}},
{&ProfilePod{Type: "peer", Name: "user", Color: "blue"}},
}
for i, c := range cases {
cpy := c.profile.Copy()
if !reflect.DeepEqual(cpy, c.profile) {
t.Errorf("ProfilePod Copy test case %v, profile structs are not equal: \ncopy: %v, \noriginal: %v", i, cpy, c.profile)
continue
}
cpy.PeerIDs[0] = ""
if reflect.DeepEqual(cpy, c.profile) {
t.Errorf("ProfilePod Copy test case %v, editing one profile struct should not affect the other: \ncopy: %v, \noriginal: %v", i, cpy, c.profile)
continue
}
}
}

func TestProfileCopyPeerIDs(t *testing.T) {
// build off DefaultProfile so we can test that the profile Copy
// actually copies over correctly (ie, deeply)
p := DefaultProfile()
p.PeerIDs = []string{"1", "2", "3"}

cpy := p.Copy()
if !reflect.DeepEqual(cpy, p) {
t.Errorf("ProfilePodCopyPeerIDs, structs are not equal: \ncopy: %v, \noriginal: %v", cpy, p)
}
cpy.PeerIDs[0] = ""
if reflect.DeepEqual(cpy, p) {
t.Errorf("ProfilePodCopyPeerIDs, editing one profile struct should not affect the other: \ncopy: %v, \noriginal: %v", cpy, p)
}
}

func TestProfileSetField(t *testing.T) {
p := ProfilePod{
Created: time.Now(),
Updated: time.Now(),
Type: "peer",
}
p.SetField("email", "user@example.com")

expect := ProfilePod{
Created: p.Created,
Updated: p.Updated,
Type: "peer",
Email: "user@example.com",
}
if !reflect.DeepEqual(p, expect) {
t.Errorf("ProfilePod SetField email, structs are not equal: \nactual: %v, \nexpect: %v", p, expect)
}

p.SetField("name", "user")
expect = ProfilePod{
Created: p.Created,
Updated: p.Updated,
Type: "peer",
Email: "user@example.com",
Name: "user",
}
if !reflect.DeepEqual(p, expect) {
t.Errorf("ProfilePod SetField name, structs are not equal: \nactual: %v, \nexpect: %v", p, expect)
}

p.SetField("email", "me@example.com")
expect = ProfilePod{
Created: p.Created,
Updated: p.Updated,
Type: "peer",
Email: "me@example.com",
Name: "user",
}
if !reflect.DeepEqual(p, expect) {
t.Errorf("ProfilePod SetField email again, structs are not equal: \nactual: %v, \nexpect: %v", p, expect)
}
}

0 comments on commit 1b13e0e

Please sign in to comment.