Skip to content

Commit

Permalink
refactor(profile): profile has separate function for saving peername
Browse files Browse the repository at this point in the history
Merge pull request #270 from qri-io/profile
  • Loading branch information
ramfox authored Feb 19, 2018
2 parents b51a487 + 5c4e987 commit 66d7518
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 68 deletions.
6 changes: 5 additions & 1 deletion api/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ func TestServerRoutes(t *testing.T) {
}{
{"GET", "/status", "", "statusResponse.json", 200},
{"GET", "/list", "", "listResponse.json", 200},
{"GET", "/profile", "", "profileResponseInitial.json", 200},
{"POST", "/profile", "profileRequest.json", "profileResponse.json", 200},
{"GET", "/profile", "", "profileResponse.json", 200},
{"GET", "/me", "", "profileResponse.json", 200},
{"POST", "/add", "addRequestFromURL.json", "addResponseFromURL.json", 200},
{"GET", "/me/family_relationships", "", "getResponseFamilyRelationships.json", 200},
Expand Down Expand Up @@ -176,6 +176,10 @@ func testMimeMultipart(t *testing.T, server *httptest.Server, client *http.Clien
"message": "want to expand this list to include more cities",
},
},
{"GET", "/profile", "testdata/profileResponseInitial.json", 200,
map[string]string{},
map[string]string{},
},
{"POST", "/save", "testdata/saveResponseMeta.json", 200,
map[string]string{
"metadata": "testdata/cities/meta_update.json",
Expand Down
2 changes: 1 addition & 1 deletion api/testdata/photoResponse.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"color": "",
"thumb": "/map/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1",
"profile": "/map/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1",
"poster": "",
"poster": "/",
"twitter": ""
},
"meta": {
Expand Down
4 changes: 2 additions & 2 deletions api/testdata/profileRequest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"email": "[email protected]",
"name": "test name",
"description": "test description",
"homeUrl": "test url",
"color": "test",
"homeUrl": "http://test.url",
"color": "default",
"thumb": "/",
"profile": "/",
"poster": "/",
Expand Down
3 changes: 0 additions & 3 deletions api/testdata/profileRequestType.json

This file was deleted.

10 changes: 5 additions & 5 deletions api/testdata/profileResponse.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
"email": "[email protected]",
"name": "test name",
"description": "test description",
"homeUrl": "test url",
"color": "test",
"thumb": "/",
"profile": "/",
"poster": "/",
"homeUrl": "http://test.url",
"color": "default",
"thumb": "/map/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1",
"profile": "/map/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1",
"poster": "/map/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL",
"twitter": "test"
},
"meta": {
Expand Down
6 changes: 3 additions & 3 deletions api/testdata/profileResponseInitial.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
"description": "",
"homeUrl": "",
"color": "",
"thumb": "/map/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1",
"profile": "/map/QmRdexT18WuAKVX3vPusqmJTWLeNSeJgjmMbaF5QLGHna1",
"poster": "/map/QmdJgfxj4rocm88PLeEididS7V2cc9nQosA46RpvAnWvDL",
"thumb": "",
"profile": "",
"poster": "",
"twitter": ""
},
"meta": {
Expand Down
6 changes: 0 additions & 6 deletions api/testdata/profileResponseTypeError.json

This file was deleted.

4 changes: 0 additions & 4 deletions cmd/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ var profileSetCmd = &cobra.Command{
err = json.NewDecoder(dataFile).Decode(set)
ExitIfErr(err)

if set.Peername != "" {
p.Peername = set.Peername
}
if set.Name != "" {
p.Name = set.Name
}
Expand Down Expand Up @@ -133,7 +130,6 @@ func init() {

func editableProfileJSONBytes(res *core.Profile) ([]byte, error) {
mapr := map[string]interface{}{
"peername": res.Peername,
"name": res.Name,
"description": res.Description,
"homeUrl": res.HomeURL,
Expand Down
1 change: 1 addition & 0 deletions cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ overwrite this info.`,
ExitIfErr(err)

res := &core.Profile{}
err = pr.SavePeername(p, res)
err = pr.SaveProfile(p, res)
ExitIfErr(err)
},
Expand Down
212 changes: 169 additions & 43 deletions core/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"io/ioutil"
"net/http"
"net/rpc"
"os"
"time"

"github.com/qri-io/cafs/memfs"
"github.com/qri-io/jsonschema"
"github.com/qri-io/qri/repo"
"github.com/qri-io/qri/repo/profile"
)
Expand Down Expand Up @@ -106,35 +108,137 @@ func (r *ProfileRequests) GetProfile(in *bool, res *Profile) error {
return nil
}

// SaveProfile stores changes to this peer's profile
func (r *ProfileRequests) SaveProfile(p *Profile, res *Profile) error {
if r.cli != nil {
return r.cli.Call("ProfileRequests.SaveProfile", p, res)
}
if p == nil {
return fmt.Errorf("profile required for update")
// AssignEditable - help with this name plz
// don't really want to call it assign cause that implies it would change every field
// AssignEditable collapses all the editable properties of a Profile onto one.
// this is directly inspired by Javascript's Object.assign
// Editable Fields:
// Peername
// Email
// Name
// Description
// HomeURL
// Color
// Thumb
// Profile
// Poster
// Twitter
func (p *Profile) AssignEditable(profiles ...*Profile) {
for _, pf := range profiles {
if pf == nil {
continue
}
if pf.Peername != "" {
p.Peername = pf.Peername
}
if pf.Email != "" {
p.Email = pf.Email
}
if pf.Name != "" {
p.Name = pf.Name
}
if pf.Description != "" {
p.Description = pf.Description
}
if pf.HomeURL != "" {
p.HomeURL = pf.HomeURL
}
if pf.Color != "" {
p.Color = pf.Color
}
if pf.Thumb != "" {
p.Thumb = pf.Thumb
}
if pf.Profile != "" {
p.Profile = pf.Profile
}
if pf.Poster != "" {
p.Poster = pf.Poster
}
if pf.Twitter != "" {
p.Twitter = pf.Twitter
}
}
}

_p, err := unmarshalProfile(p)
// ValidateProfile validates all fields of profile
// returning first error found
func (p *Profile) ValidateProfile() error {
// read profileSchema from testdata/profileSchema.json
// marshal to json?
gp := os.Getenv("GOPATH")
filepath := gp + "/src/github.com/qri-io/qri/core/schemas/profileSchema.json"
f, err := os.Open(filepath)
if err != nil {
return err
return fmt.Errorf("error opening schemas/profileSchema.json: %s", err)
}
defer f.Close()

if err := r.repo.SaveProfile(_p); err != nil {
return err
profileSchema, err := ioutil.ReadAll(f)
if err != nil {
return fmt.Errorf("error reading profileSchema", err)
}

profile, err := r.repo.Profile()
// unmarshal to rootSchema
rs := &jsonschema.RootSchema{}
if err := json.Unmarshal(profileSchema, rs); err != nil {
return fmt.Errorf("error unmarshaling profileSchema to RootSchema: %s", err)
}
profile, err := json.Marshal(p)
if err != nil {
return err
return fmt.Errorf("error marshaling profile to json: %s", err)
}
if errors := rs.ValidateBytes(profile); len(errors) > 0 {
return fmt.Errorf("%s", errors)
}
return nil
}

p2, err := marshalProfile(profile)
if err != nil {
return err
// SavePeername updates the profile to include the peername
// warning! SHOULD ONLY BE CALLED ONCE: WHEN INITIALIZING/SETTING UP THE REPO
func (r *ProfileRequests) SavePeername(p *Profile, res *Profile) error {
if p == nil {
return fmt.Errorf("profile required to save peername")
}
if p.Peername == "" {
return fmt.Errorf("peername required")
}

// ensure only fields we want to save are being passed to saveProfile:
pro := &Profile{
Peername: p.Peername,
}

if err := r.saveProfile(pro, res); err != nil {
return fmt.Errorf("error saving profile: %s", err)
}

return nil
}

// SaveProfile stores changes to this peer's editable profile profile
func (r *ProfileRequests) SaveProfile(p *Profile, res *Profile) error {
if r.cli != nil {
return r.cli.Call("ProfileRequests.SaveProfile", p, res)
}
if p == nil {
return fmt.Errorf("profile required for update")
}

// to ensure only the fields we want to be editable are passed to saveProfile:
pro := &Profile{
Name: p.Name,
Email: p.Email,
Description: p.Description,
HomeURL: p.HomeURL,
Color: p.Color,
Twitter: p.Twitter,
}

if err := r.saveProfile(pro, res); err != nil {
return fmt.Errorf("error saving profile: %s", err)
}

*res = *p2
return nil
}

Expand Down Expand Up @@ -169,30 +273,20 @@ func (r *ProfileRequests) SetProfilePhoto(p *FileParams, res *Profile) error {
return fmt.Errorf("file size too large. max size is 250kb")
}

pro, err := r.repo.Profile()
if err != nil {
return fmt.Errorf("error loading profile: %s", err.Error())
}

path, err := r.repo.Store().Put(memfs.NewMemfileBytes(p.Filename, data), true)
if err != nil {
return fmt.Errorf("error saving photo: %s", err.Error())
}

pro.Profile = path
// TODO - resize photo
pro.Thumb = path

if err := r.repo.SaveProfile(pro); err != nil {
return fmt.Errorf("error saving profile: %s", err.Error())
pro := &Profile{
Profile: path.String(),
// TODO - resize photo
Thumb: path.String(),
}

_p, err := marshalProfile(pro)
if err != nil {
return err
if err := r.saveProfile(pro, res); err != nil {
return fmt.Errorf("error saving profile: %s", err)
}

*res = *_p
return nil
}

Expand Down Expand Up @@ -220,27 +314,59 @@ func (r *ProfileRequests) SetPosterPhoto(p *FileParams, res *Profile) error {
return fmt.Errorf("file size too large. max size is 2Mb")
}

pro, err := r.repo.Profile()
if err != nil {
return fmt.Errorf("error loading profile: %s", err.Error())
}

path, err := r.repo.Store().Put(memfs.NewMemfileBytes(p.Filename, data), true)
if err != nil {
return fmt.Errorf("error saving photo: %s", err.Error())
}

pro.Poster = path
pro := &Profile{
Poster: path.String(),
}

if err := r.saveProfile(pro, res); err != nil {
return fmt.Errorf("error saving profile: %s", err)
}

return nil
}

// saveProfile stores changes to this peer's profile
// does not check to see if inputs are valid
func (r *ProfileRequests) saveProfile(p *Profile, res *Profile) error {
if p == nil {
return fmt.Errorf("profile required for update")
}
pro := &Profile{}
if err := r.GetProfile(nil, pro); err != nil {
return fmt.Errorf("error getting previous profile: %s", err)
}

pro.AssignEditable(p)

if err := r.repo.SaveProfile(pro); err != nil {
return fmt.Errorf("error saving profile: %s", err.Error())
// validate new Profile inputs
if err := p.ValidateProfile(); err != nil {
return fmt.Errorf("error validating profile: %s", err)
}

_p, err := marshalProfile(pro)
_p, err := unmarshalProfile(pro)
if err != nil {
return err
}

*res = *_p
if err := r.repo.SaveProfile(_p); err != nil {
return err
}

profile, err := r.repo.Profile()
if err != nil {
return err
}
p2, err := marshalProfile(profile)
if err != nil {
return err
}

*res = *p2
return nil

}
Loading

0 comments on commit 66d7518

Please sign in to comment.