From 087a452730710d419f41a79043bc5e880f171e04 Mon Sep 17 00:00:00 2001 From: Billy Lynch Date: Sat, 25 Jun 2016 20:27:06 -0400 Subject: [PATCH] add support for OAuth Grant Authorizations API GitHub API docs: https://developer.github.com/v3/oauth_authorizations Fixes #348. Closes #388. Change-Id: I795b1c0e10bde10a1bc9aaa4594af4c91e07962d --- github/authorizations.go | 78 +++++++++++++++++++++++++++++++++++ github/authorizations_test.go | 57 +++++++++++++++++++++++++ github/github.go | 3 ++ 3 files changed, 138 insertions(+) diff --git a/github/authorizations.go b/github/authorizations.go index 43af06c..2839f93 100644 --- a/github/authorizations.go +++ b/github/authorizations.go @@ -85,6 +85,20 @@ func (a AuthorizationApp) String() string { return Stringify(a) } +// Grant represents an OAuth application that has been granted access to an account. +type Grant struct { + ID *int `json:"id,omitempty"` + URL *string `json:"url,omitempty"` + App *AuthorizationApp `json:"app,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + UpdatedAt *Timestamp `json:"updated_at,omitempty"` + Scopes []string `json:"scopes,omitempty"` +} + +func (g Grant) String() string { + return Stringify(g) +} + // AuthorizationRequest represents a request to create an authorization. type AuthorizationRequest struct { Scopes []Scope `json:"scopes,omitempty"` @@ -321,3 +335,67 @@ func (s *AuthorizationsService) Revoke(clientID string, token string) (*Response return s.client.Do(req, nil) } + +// ListGrants lists the set of OAuth applications that have been granted +// access to a user's account. This will return one entry for each application +// that has been granted access to the account, regardless of the number of +// tokens an application has generated for the user. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-grants +func (s *AuthorizationsService) ListGrants() ([]*Grant, *Response, error) { + req, err := s.client.NewRequest("GET", "applications/grants", nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeOAuthGrantAuthorizationsPreview) + + grants := []*Grant{} + resp, err := s.client.Do(req, &grants) + if err != nil { + return nil, resp, err + } + + return grants, resp, err +} + +// GetGrant gets a single OAuth application grant. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-grant +func (s *AuthorizationsService) GetGrant(id int) (*Grant, *Response, error) { + u := fmt.Sprintf("applications/grants/%d", id) + 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", mediaTypeOAuthGrantAuthorizationsPreview) + + grant := new(Grant) + resp, err := s.client.Do(req, grant) + if err != nil { + return nil, resp, err + } + + return grant, resp, err +} + +// DeleteGrant deletes an OAuth application grant. Deleting an application's +// grant will also delete all OAuth tokens associated with the application for +// the user. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-a-grant +func (s *AuthorizationsService) DeleteGrant(id int) (*Response, error) { + u := fmt.Sprintf("applications/grants/%d", id) + 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", mediaTypeOAuthGrantAuthorizationsPreview) + + return s.client.Do(req, nil) +} diff --git a/github/authorizations_test.go b/github/authorizations_test.go index 9c62b77..b3d4e91 100644 --- a/github/authorizations_test.go +++ b/github/authorizations_test.go @@ -249,3 +249,60 @@ func TestAuthorizationsService_Revoke(t *testing.T) { t.Errorf("Authorizations.Revoke returned error: %v", err) } } + +func TestListGrants(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/applications/grants", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeOAuthGrantAuthorizationsPreview) + fmt.Fprint(w, `[{"id": 1}]`) + }) + + got, _, err := client.Authorizations.ListGrants() + if err != nil { + t.Errorf("OAuthAuthorizations.ListGrants returned error: %v", err) + } + + want := []*Grant{{ID: Int(1)}} + if !reflect.DeepEqual(got, want) { + t.Errorf("OAuthAuthorizations.ListGrants = %+v, want %+v", got, want) + } +} + +func TestGetGrant(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/applications/grants/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", mediaTypeOAuthGrantAuthorizationsPreview) + fmt.Fprint(w, `{"id": 1}`) + }) + + got, _, err := client.Authorizations.GetGrant(1) + if err != nil { + t.Errorf("OAuthAuthorizations.GetGrant returned error: %v", err) + } + + want := &Grant{ID: Int(1)} + if !reflect.DeepEqual(got, want) { + t.Errorf("OAuthAuthorizations.GetGrant = %+v, want %+v", got, want) + } +} + +func TestDeleteGrant(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/applications/grants/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testHeader(t, r, "Accept", mediaTypeOAuthGrantAuthorizationsPreview) + }) + + _, err := client.Authorizations.DeleteGrant(1) + if err != nil { + t.Errorf("OAuthAuthorizations.DeleteGrant returned error: %v", err) + } +} diff --git a/github/github.go b/github/github.go index 3fd4b97..5a4afcf 100644 --- a/github/github.go +++ b/github/github.go @@ -81,6 +81,9 @@ const ( // https://developer.github.com/changes/2016-06-14-repository-invitations/ mediaTypeRepositoryInvitationsPreview = "application/vnd.github.swamp-thing-preview+json" + + // https://developer.github.com/changes/2016-04-21-oauth-authorizations-grants-api-preview/ + mediaTypeOAuthGrantAuthorizationsPreview = "application/vnd.github.damage-preview+json" ) // A Client manages communication with the GitHub API.