From 76106691023e9d5b80036fb38a19f634d1a7910d Mon Sep 17 00:00:00 2001 From: Will Norris Date: Mon, 25 Aug 2014 14:20:07 -0700 Subject: [PATCH] add support for new team membership API --- github/github.go | 5 +++ github/orgs_teams.go | 86 +++++++++++++++++++++++++++++++++++++++ github/orgs_teams_test.go | 58 ++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) diff --git a/github/github.go b/github/github.go index 224a07e..f5cd1b9 100644 --- a/github/github.go +++ b/github/github.go @@ -34,6 +34,11 @@ const ( mediaTypeV3 = "application/vnd.github.v3+json" defaultMediaType = "application/octet-stream" + + // Media Type values to access preview APIs + + // https://developer.github.com/changes/2014-08-05-team-memberships-api/ + mediaTypeTeamMembershipPreview = "application/vnd.github.the-wasp-preview+json" ) // A Client manages communication with the GitHub API. diff --git a/github/orgs_teams.go b/github/orgs_teams.go index dc64fa5..ed5d43a 100644 --- a/github/orgs_teams.go +++ b/github/orgs_teams.go @@ -23,6 +23,17 @@ func (t Team) String() string { return Stringify(t) } +// TeamMembership represents the status an a user's membership in a team. +type TeamMembership struct { + URL *string `json:"url,omitempty"` + // Status is the user's status within the team. Possible values are: "active", "pending" + Status *string `json:"status,omitempty"` +} + +func (t TeamMembership) String() string { + return Stringify(t) +} + // ListTeams lists all of the teams for an organization. // // GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-teams @@ -251,3 +262,78 @@ func (s *OrganizationsService) RemoveTeamRepo(team int, owner string, repo strin return s.client.Do(req, nil) } + +// GetTeamMembership returns the membership status for a user in a team. +// +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership +func (s *OrganizationsService) GetTeamMembership(team int, user string) (*TeamMembership, *Response, error) { + u := fmt.Sprintf("teams/%v/memberships/%v", team, user) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeTeamMembershipPreview) + + t := new(TeamMembership) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// AddTeamMembership adds or invites a user to a team. +// +// In order to add a membership between a user and a team, the authenticated +// user must have 'admin' permissions to the team or be an owner of the +// organization that the team is associated with. +// +// If the user is already a part of the team's organization (meaning they're on +// at least one other team in the organization), this endpoint will add the +// user to the team. +// +// If the user is completely unaffiliated with the team's organization (meaning +// they're on none of the organization's teams), this endpoint will send an +// invitation to the user via email. This newly-created membership will be in +// the "pending" state until the user accepts the invitation, at which point +// the membership will transition to the "active" state and the user will be +// added as a member of the team. +// +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-membership +func (s *OrganizationsService) AddTeamMembership(team int, user string) (*TeamMembership, *Response, error) { + u := fmt.Sprintf("teams/%v/memberships/%v", team, user) + req, err := s.client.NewRequest("PUT", u, nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeTeamMembershipPreview) + + t := new(TeamMembership) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// RemoveTeamMembership removes a user from a team. +// +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#remove-team-membership +func (s *OrganizationsService) RemoveTeamMembership(team int, user string) (*Response, error) { + u := fmt.Sprintf("teams/%v/memberships/%v", team, user) + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeTeamMembershipPreview) + + return s.client.Do(req, nil) +} diff --git a/github/orgs_teams_test.go b/github/orgs_teams_test.go index c62aedc..d413697 100644 --- a/github/orgs_teams_test.go +++ b/github/orgs_teams_test.go @@ -435,3 +435,61 @@ func TestOrganizationsService_RemoveTeamRepo_invalidOwner(t *testing.T) { _, err := client.Organizations.RemoveTeamRepo(1, "%", "r") testURLParseError(t, err) } + +func TestOrganizationsService_GetTeamMembership(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeTeamMembershipPreview) + fmt.Fprint(w, `{"url":"u", "status":"active"}`) + }) + + membership, _, err := client.Organizations.GetTeamMembership(1, "u") + if err != nil { + t.Errorf("Organizations.GetTeamMembership returned error: %v", err) + } + + want := &TeamMembership{URL: String("u"), Status: String("active")} + if !reflect.DeepEqual(membership, want) { + t.Errorf("Organizations.GetTeamMembership returned %+v, want %+v", membership, want) + } +} + +func TestOrganizationsService_AddTeamMembership(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + testHeader(t, r, "Accept", mediaTypeTeamMembershipPreview) + fmt.Fprint(w, `{"url":"u", "status":"pending"}`) + }) + + membership, _, err := client.Organizations.AddTeamMembership(1, "u") + if err != nil { + t.Errorf("Organizations.AddTeamMembership returned error: %v", err) + } + + want := &TeamMembership{URL: String("u"), Status: String("pending")} + if !reflect.DeepEqual(membership, want) { + t.Errorf("Organizations.AddTeamMembership returned %+v, want %+v", membership, want) + } +} + +func TestOrganizationsService_RemoveTeamMembership(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testHeader(t, r, "Accept", mediaTypeTeamMembershipPreview) + w.WriteHeader(http.StatusNoContent) + }) + + _, err := client.Organizations.RemoveTeamMembership(1, "u") + if err != nil { + t.Errorf("Organizations.RemoveTeamMembership returned error: %v", err) + } +}