From a046146166e5822a14962082961a2eb737f8ef47 Mon Sep 17 00:00:00 2001 From: Chuck D'Antonio Date: Tue, 11 Feb 2025 11:37:01 -0500 Subject: [PATCH] Adapts member flow for API changes --- setup/pkg/fieldlabs/members.go | 218 +++++++++++++++++---------------- 1 file changed, 111 insertions(+), 107 deletions(-) diff --git a/setup/pkg/fieldlabs/members.go b/setup/pkg/fieldlabs/members.go index 6a02ad98..302b5079 100644 --- a/setup/pkg/fieldlabs/members.go +++ b/setup/pkg/fieldlabs/members.go @@ -60,14 +60,14 @@ func (e *EnvironmentManager) getMembersMap() (map[string]MemberList, error) { return nil, errors.Wrap(err, "get members") } - membersJson, _ := json.Marshal(members) - fmt.Sprintf("members: %s", membersJson) + membersJson, _ := json.Marshal(members) + fmt.Sprintf("members: %s", membersJson) membersMap := make(map[string]MemberList) for i := 0; i < len(members); i += 1 { - memberJson, _ := json.Marshal(members) - fmt.Sprintf("member: %s", memberJson) - fmt.Sprintf("member: %s", members[i].Email) + memberJson, _ := json.Marshal(members) + fmt.Sprintf("member: %s", memberJson) + fmt.Sprintf("member: %s", members[i].Email) membersMap[members[i].Email] = members[i] } return membersMap, nil @@ -75,15 +75,15 @@ func (e *EnvironmentManager) getMembersMap() (map[string]MemberList, error) { // Delete team members created with multi-player mode func (e *EnvironmentManager) DeleteMember(id string) error { - url := fmt.Sprintf("%s/v1/team/member/%s", e.Params.IDOrigin, id) + requestUrl := fmt.Sprintf("%s/v1/team/member?id=%s", e.Params.IDOrigin, id) req, err := http.NewRequest( "DELETE", - url, + requestUrl, nil, ) if err != nil { - return errors.Wrap(err, fmt.Sprintf("DELETE %s/v1/team/member?user_id=%s", e.Params.IDOrigin, id)) + return errors.Wrap(err, fmt.Sprintf("DELETE %s", requestUrl)) } req.Header.Set("Authorization", e.Params.SessionToken) req.Header.Set("Accept", "application/json") @@ -98,13 +98,13 @@ func (e *EnvironmentManager) DeleteMember(id string) error { panic(err.Error()) } if resp.StatusCode != 204 { - return fmt.Errorf("DELETE /v1/team/member/%s %d: %s", id, resp.StatusCode, body) + return fmt.Errorf("DELETE %s %d: %s", requestUrl, resp.StatusCode, body) } return nil } func (e *EnvironmentManager) addMember(members map[string]MemberList, policies map[string]string) error { - inviteEmail := e.Params.ParticipantId + "@replicated-labs.com" + inviteEmail := e.Params.ParticipantId + "@replicated-labs.com" err := e.inviteMember(inviteEmail, members, policies) if err != nil { return err @@ -136,93 +136,106 @@ func (e *EnvironmentManager) addMember(members map[string]MemberList, policies m return nil } -type AcceptBody struct { - InviteId string `json:"invite_id"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Password string `json:"password"` - ReplaceAccount bool `json:"replace_account"` - FromTeamSelection bool `json:"from_team_selection"` + +type VerifyResponse struct { + Token string `json:"token"` } -func (e *EnvironmentManager) acceptInvite(inviteId string, participantId string, vr *VerifyResponse) error { - h := sha256.Sum256([]byte(participantId)) - sum := fmt.Sprintf("%x", h) +type SignupResponse struct { + Token string `json:"token"` +} - ab := AcceptBody{InviteId: inviteId, FirstName: "Repl", LastName: "Replicated", Password: string(sum[0:20]), ReplaceAccount: false, FromTeamSelection: true} - acceptBodyBytes, err := json.Marshal(ab) +func (e *EnvironmentManager) signupMember(inviteEmail string) (*SignupResponse, error) { + signupBody := map[string]string{ + "email": inviteEmail, + } + signupBodyBytes, err := json.Marshal(signupBody) if err != nil { - return errors.Wrap(err, "marshal accept body") + return nil, errors.Wrap(err, "marshal signup body") } + requestUrl := fmt.Sprintf("%s/vendor/v1/signup", e.Params.IDOrigin) req, err := http.NewRequest( "POST", - fmt.Sprintf("%s/vendor/v1/signup/accept-invite", e.Params.IDOrigin), - bytes.NewReader(acceptBodyBytes), + requestUrl, + bytes.NewReader(signupBodyBytes), ) if err != nil { - return errors.Wrap(err, "build accept request") + return nil, errors.Wrap(err, "build signup request") } req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { - return errors.Wrap(err, "send accept request") + return nil, errors.Wrap(err, "send signup request") } defer resp.Body.Close() if resp.StatusCode != 201 { body, _ := ioutil.ReadAll(resp.Body) - return fmt.Errorf("POST /v1/signup/accept-invite %d: %s", resp.StatusCode, body) + return nil, fmt.Errorf("POST %s %d: %s", requestUrl, resp.StatusCode, body) } - return nil -} + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, errors.Wrap(err, "read body") + } + var body SignupResponse + if err := json.NewDecoder(bytes.NewReader(bodyBytes)).Decode(&body); err != nil { + return nil, errors.Wrap(err, "decode body") + } + return &body, nil -type InvitedTeams struct { - Teams []struct { - Id string `json:"id"` - Name string `json:"name"` - InviteId string `json:"invite_id"` - } `json:"invited_teams"` } -func (e *EnvironmentManager) captureInvite(vr *VerifyResponse) (*Invite, error) { - e.Log.Verbose() +func (e *EnvironmentManager) inviteMember(inviteEmail string, members map[string]MemberList, policies map[string]string) error { + if _, memberExists := members[inviteEmail]; memberExists { + // This should never happen? + return nil + } + inviteBody := map[string]string{ + "email": inviteEmail, + "policy_id": policies[e.Params.ParticipantId], + } + inviteBodyBytes, err := json.Marshal(inviteBody) + if err != nil { + return errors.Wrap(err, "marshal invite body") + } + requestUrl := fmt.Sprintf("%s/vendor/v1/team/invite", e.Params.IDOrigin) req, err := http.NewRequest( - "GET", - fmt.Sprintf("%s/vendor/v1/signup/teams", e.Params.IDOrigin, inviteId), - nil, + "POST", + requestUrl, + bytes.NewReader(inviteBodyBytes), ) if err != nil { - return nil, errors.Wrap(err, "build signup teams request") + return errors.Wrap(err, "build invite request") } + req.Header.Set("Authorization", e.Params.SessionToken) req.Header.Set("Accept", "application/json") - req.Header.Set("Authorization", vr.Token) + req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { - return nil, errors.Wrap(err, "getting the invite") + return errors.Wrap(err, fmt.Sprintf("send invite request: %s", requestUrl)) } defer resp.Body.Close() - - if resp.StatusCode != 200 { - body, _ := ioutil.ReadAll(resp.Body) - return nil, fmt.Errorf("GET /v1/invite/%s %d: %s", inviteId, resp.StatusCode, body) - } - bodyBytes, err := ioutil.ReadAll(resp.Body) - e.Log.Debug(fmt.Sprintf("GET /v1/invite/%s %d: %s", inviteId, resp.StatusCode, bodyBytes)) - if err != nil { - return nil, errors.Wrap(err, "read body") + // rate limit returned when already invited + if resp.StatusCode == 429 { + e.Log.ActionWithoutSpinner("Skipping invite %q due to 429 error", inviteEmail) + return nil } - var body Invite - if err := json.NewDecoder(bytes.NewReader(bodyBytes)).Decode(&body); err != nil { - return nil, errors.Wrap(err, "decode body") + if resp.StatusCode != 204 { + body, _ := ioutil.ReadAll(resp.Body) + return fmt.Errorf("POST %s %d: %s", requestUrl, resp.StatusCode, body) } - return &body, nil + return nil } -type VerifyResponse struct { - Token string `json:"token"` +type InvitedTeams struct { + Teams []struct { + Id string `json:"id"` + Name string `json:"name"` + InviteId string `json:"invite_id"` + } `json:"invited_teams"` } func (e *EnvironmentManager) verifyMember(sr *SignupResponse) (*VerifyResponse, error) { @@ -233,13 +246,14 @@ func (e *EnvironmentManager) verifyMember(sr *SignupResponse) (*VerifyResponse, if err != nil { return nil, errors.Wrap(err, "marshal verify body") } + requestUrl := fmt.Sprintf("%s/vendor/v1/signup/verify", e.Params.IDOrigin) req, err := http.NewRequest( "POST", - fmt.Sprintf("%s/vendor/v1/signup/verify", e.Params.IDOrigin), + requestUrl, bytes.NewReader(verifyBodyBytes), ) if err != nil { - return nil, errors.Wrap(err, "build verify request") + return nil, errors.Wrap(err, fmt.Sprintf("build verify request: %s", requestUrl)) } req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") @@ -252,7 +266,7 @@ func (e *EnvironmentManager) verifyMember(sr *SignupResponse) (*VerifyResponse, if resp.StatusCode != 201 { body, _ := ioutil.ReadAll(resp.Body) - return nil, fmt.Errorf("POST /vendor/v1/signup/verify %d: %s", resp.StatusCode, body) + return nil, fmt.Errorf("POST %s %d: %s", requestUrl, resp.StatusCode, body) } bodyBytes, err := ioutil.ReadAll(resp.Body) if err != nil { @@ -262,93 +276,83 @@ func (e *EnvironmentManager) verifyMember(sr *SignupResponse) (*VerifyResponse, if err := json.NewDecoder(bytes.NewReader(bodyBytes)).Decode(&body); err != nil { return nil, errors.Wrap(err, "decode body") } - e.Log.Debug(fmt.Sprintf("POST /vendor/v1/signup/verify %d: %s", resp.StatusCode, body)) return &body, nil } -type SignupResponse struct { - Token string `json:"token"` -} - -func (e *EnvironmentManager) signupMember(inviteEmail string) (*SignupResponse, error) { - signupBody := map[string]string{ - "email": inviteEmail, - } - signupBodyBytes, err := json.Marshal(signupBody) - if err != nil { - return nil, errors.Wrap(err, "marshal signup body") - } +func (e *EnvironmentManager) captureInvite(vr *VerifyResponse) (*InvitedTeams, error) { + e.Log.Verbose() + requestUrl := fmt.Sprintf("%s/vendor/v1/signup/teams", e.Params.IDOrigin) req, err := http.NewRequest( - "POST", - fmt.Sprintf("%s/vendor/v1/signup", e.Params.IDOrigin), - bytes.NewReader(signupBodyBytes), + "GET", + requestUrl, + nil, ) if err != nil { - return nil, errors.Wrap(err, "build signup request") + return nil, errors.Wrap(err, "build signup teams request") } req.Header.Set("Accept", "application/json") - req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", vr.Token) resp, err := http.DefaultClient.Do(req) if err != nil { - return nil, errors.Wrap(err, "send signup request") + return nil, errors.Wrap(err, "getting the invite") } defer resp.Body.Close() - if resp.StatusCode != 201 { + if resp.StatusCode != 200 { body, _ := ioutil.ReadAll(resp.Body) - return nil, fmt.Errorf("POST /v1/signup %d: %s", resp.StatusCode, body) + return nil, fmt.Errorf("GET %s %d: %s", requestUrl, resp.StatusCode, body) } bodyBytes, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, errors.Wrap(err, "read body") } - var body SignupResponse + var body InvitedTeams if err := json.NewDecoder(bytes.NewReader(bodyBytes)).Decode(&body); err != nil { return nil, errors.Wrap(err, "decode body") } return &body, nil +} +type AcceptBody struct { + InviteId string `json:"invite_id"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Password string `json:"password"` + ReplaceAccount bool `json:"replace_account"` + FromTeamSelection bool `json:"from_team_selection"` } -func (e *EnvironmentManager) inviteMember(inviteEmail string, members map[string]MemberList, policies map[string]string) error { - if _, memberExists := members[inviteEmail]; memberExists { - // This should never happen? - return nil - } - inviteBody := map[string]string{ - "email": inviteEmail, - "policy_id": policies[e.Params.ParticipantId], - } - inviteBodyBytes, err := json.Marshal(inviteBody) +func (e *EnvironmentManager) acceptInvite(invite *InvitedTeams, participantId string, vr *VerifyResponse) error { + h := sha256.Sum256([]byte(participantId)) + sum := fmt.Sprintf("%x", h) + ab := AcceptBody{InviteId: (*invite).Teams[0].InviteId, FirstName: "Instruqt", LastName: "Participant", Password: string(sum[0:20]), ReplaceAccount: false, FromTeamSelection: true} + acceptBodyBytes, err := json.Marshal(ab) if err != nil { - return errors.Wrap(err, "marshal invite body") + return errors.Wrap(err, "marshal accept body") } + + requestUrl := fmt.Sprintf("%s/vendor/v1/signup/accept-invite", e.Params.IDOrigin) req, err := http.NewRequest( "POST", - fmt.Sprintf("%s/vendor/v1/team/invite", e.Params.IDOrigin), - bytes.NewReader(inviteBodyBytes), + requestUrl, + bytes.NewReader(acceptBodyBytes), ) if err != nil { - return errors.Wrap(err, "build invite request") + return errors.Wrap(err, "build accept request") } - req.Header.Set("Authorization", e.Params.SessionToken) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { - return errors.Wrap(err, "send invite request") + return errors.Wrap(err, fmt.Sprintf("send accept request: %s", requestUrl)) } defer resp.Body.Close() - // rate limit returned when already invited - if resp.StatusCode == 429 { - e.Log.ActionWithoutSpinner("Skipping invite %q due to 429 error", inviteEmail) - return nil - } - if resp.StatusCode != 204 { + + if resp.StatusCode != 201 { body, _ := ioutil.ReadAll(resp.Body) - return fmt.Errorf("POST /team/invite %d: %s", resp.StatusCode, body) + return fmt.Errorf("POST %s %d: %s", requestUrl, resp.StatusCode, body) } return nil }