Skip to content

Commit

Permalink
feat: add/remove organization member to/from a team (#87)
Browse files Browse the repository at this point in the history
  • Loading branch information
jianyuan authored Dec 6, 2023
1 parent 5beaa3f commit c7b30d0
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 0 deletions.
2 changes: 2 additions & 0 deletions sentry/sentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ type Client struct {
ProjectFilter *ProjectFilterService
ReleaseDeployments *ReleaseDeploymentsService
Teams *TeamsService
TeamMembers *TeamMembersService
}

type service struct {
Expand Down Expand Up @@ -99,6 +100,7 @@ func NewClient(httpClient *http.Client) *Client {
c.Projects = (*ProjectsService)(&c.common)
c.ReleaseDeployments = (*ReleaseDeploymentsService)(&c.common)
c.Teams = (*TeamsService)(&c.common)
c.TeamMembers = (*TeamMembersService)(&c.common)
return c
}

Expand Down
55 changes: 55 additions & 0 deletions sentry/team_members.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package sentry

import (
"context"
"fmt"
"time"
)

type TeamMember struct {
ID *string `json:"id"`
Slug *string `json:"slug"`
Name *string `json:"name"`
DateCreated *time.Time `json:"dateCreated"`
IsMember *bool `json:"isMember"`
TeamRole *string `json:"teamRole"`
Flags map[string]bool `json:"flags"`
Access []string `json:"access"`
HasAccess *bool `json:"hasAccess"`
IsPending *bool `json:"isPending"`
MemberCount *int `json:"memberCount"`
Avatar *Avatar `json:"avatar"`
}

// TeamMember provides methods for accessing Sentry team member API endpoints.
type TeamMembersService service

func (s *TeamMembersService) Create(ctx context.Context, organizationSlug string, memberId string, teamSlug string) (*TeamMember, *Response, error) {
u := fmt.Sprintf("0/organizations/%v/members/%v/teams/%v/", organizationSlug, memberId, teamSlug)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, nil, err
}

member := new(TeamMember)
resp, err := s.client.Do(ctx, req, member)
if err != nil {
return nil, resp, err
}
return member, resp, nil
}

func (s *TeamMembersService) Delete(ctx context.Context, organizationSlug string, memberId string, teamSlug string) (*TeamMember, *Response, error) {
u := fmt.Sprintf("0/organizations/%v/members/%v/teams/%v/", organizationSlug, memberId, teamSlug)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, nil, err
}

member := new(TeamMember)
resp, err := s.client.Do(ctx, req, member)
if err != nil {
return nil, resp, err
}
return member, resp, nil
}
154 changes: 154 additions & 0 deletions sentry/team_members_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package sentry

import (
"context"
"fmt"
"net/http"
"testing"

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

func TestTeamMembersService_Create(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

mux.HandleFunc("/api/0/organizations/organization_slug/members/member_id/teams/team_slug/", func(w http.ResponseWriter, r *http.Request) {
assertMethod(t, "POST", r)
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{
"id": "4502349234123",
"slug": "ancient-gabelers",
"name": "Ancient Gabelers",
"dateCreated": "2023-05-31T19:47:53.621181Z",
"isMember": true,
"teamRole": "contributor",
"flags": {
"idp:provisioned": false
},
"access": [
"alerts:read",
"event:write",
"project:read",
"team:read",
"member:read",
"project:releases",
"event:read",
"org:read"
],
"hasAccess": true,
"isPending": false,
"memberCount": 3,
"avatar": {
"avatarType": "letter_avatar",
"avatarUuid": null
}
}`)
})

ctx := context.Background()
team, _, err := client.TeamMembers.Create(ctx, "organization_slug", "member_id", "team_slug")
assert.NoError(t, err)

expected := &TeamMember{
ID: String("4502349234123"),
Slug: String("ancient-gabelers"),
Name: String("Ancient Gabelers"),
DateCreated: Time(mustParseTime("2023-05-31T19:47:53.621181Z")),
IsMember: Bool(true),
TeamRole: String("contributor"),
Flags: map[string]bool{
"idp:provisioned": false,
},
Access: []string{
"alerts:read",
"event:write",
"project:read",
"team:read",
"member:read",
"project:releases",
"event:read",
"org:read",
},
HasAccess: Bool(true),
IsPending: Bool(false),
MemberCount: Int(3),
Avatar: &Avatar{
UUID: nil,
Type: "letter_avatar",
},
}
assert.Equal(t, expected, team)
}

func TestTeamMembersService_Delete(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

mux.HandleFunc("/api/0/organizations/organization_slug/members/member_id/teams/team_slug/", func(w http.ResponseWriter, r *http.Request) {
assertMethod(t, "DELETE", r)
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{
"id": "4502349234123",
"slug": "ancient-gabelers",
"name": "Ancient Gabelers",
"dateCreated": "2023-05-31T19:47:53.621181Z",
"isMember": false,
"teamRole": null,
"flags": {
"idp:provisioned": false
},
"access": [
"alerts:read",
"event:write",
"project:read",
"team:read",
"member:read",
"project:releases",
"event:read",
"org:read"
],
"hasAccess": true,
"isPending": false,
"memberCount": 3,
"avatar": {
"avatarType": "letter_avatar",
"avatarUuid": null
}
}`)
})

ctx := context.Background()
team, _, err := client.TeamMembers.Delete(ctx, "organization_slug", "member_id", "team_slug")
assert.NoError(t, err)

expected := &TeamMember{
ID: String("4502349234123"),
Slug: String("ancient-gabelers"),
Name: String("Ancient Gabelers"),
DateCreated: Time(mustParseTime("2023-05-31T19:47:53.621181Z")),
IsMember: Bool(false),
TeamRole: nil,
Flags: map[string]bool{
"idp:provisioned": false,
},
Access: []string{
"alerts:read",
"event:write",
"project:read",
"team:read",
"member:read",
"project:releases",
"event:read",
"org:read",
},
HasAccess: Bool(true),
IsPending: Bool(false),
MemberCount: Int(3),
Avatar: &Avatar{
UUID: nil,
Type: "letter_avatar",
},
}
assert.Equal(t, expected, team)
}

0 comments on commit c7b30d0

Please sign in to comment.