Skip to content

Commit d93435a

Browse files
authored
Add Social Accounts API (#3647)
1 parent 9f2b91b commit d93435a

File tree

5 files changed

+319
-0
lines changed

5 files changed

+319
-0
lines changed

github/examples_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,19 @@ func ExampleTeamsService_ListTeams() {
173173

174174
fmt.Printf("Team %q was not found\n", teamName)
175175
}
176+
177+
func ExampleUsersService_ListUserSocialAccounts() {
178+
client := github.NewClient(nil)
179+
ctx := context.Background()
180+
opts := &github.ListOptions{}
181+
for {
182+
accounts, resp, err := client.Users.ListUserSocialAccounts(ctx, "shreyjain13", opts)
183+
if err != nil {
184+
log.Fatalf("Failed to list user social accounts: %v", err)
185+
}
186+
if resp.NextPage == 0 || len(accounts) == 0 {
187+
break
188+
}
189+
opts.Page = resp.NextPage
190+
}
191+
}

github/github-accessors.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

github/github-accessors_test.go

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

github/users_social_accounts.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright 2025 The go-github AUTHORS. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style
4+
// license that can be found in the LICENSE file.
5+
6+
package github
7+
8+
import (
9+
"context"
10+
"fmt"
11+
)
12+
13+
// SocialAccount represents a social account linked to a user.
14+
type SocialAccount struct {
15+
Provider *string `json:"provider,omitempty"`
16+
URL *string `json:"url,omitempty"`
17+
}
18+
19+
// ListSocialAccounts lists all social accounts for the authenticated user.
20+
//
21+
// GitHub API docs: https://docs.github.com/rest/users/social-accounts#list-social-accounts-for-the-authenticated-user
22+
//
23+
//meta:operation GET /user/social_accounts
24+
func (s *UsersService) ListSocialAccounts(ctx context.Context, opts *ListOptions) ([]*SocialAccount, *Response, error) {
25+
u := "user/social_accounts"
26+
u, err := addOptions(u, opts)
27+
if err != nil {
28+
return nil, nil, err
29+
}
30+
31+
req, err := s.client.NewRequest("GET", u, nil)
32+
if err != nil {
33+
return nil, nil, err
34+
}
35+
36+
var socialAccounts []*SocialAccount
37+
resp, err := s.client.Do(ctx, req, &socialAccounts)
38+
if err != nil {
39+
return nil, resp, err
40+
}
41+
42+
return socialAccounts, resp, nil
43+
}
44+
45+
// AddSocialAccounts adds social accounts for the authenticated user.
46+
//
47+
// GitHub API docs: https://docs.github.com/rest/users/social-accounts#add-social-accounts-for-the-authenticated-user
48+
//
49+
//meta:operation POST /user/social_accounts
50+
func (s *UsersService) AddSocialAccounts(ctx context.Context, accountURLs []string) ([]*SocialAccount, *Response, error) {
51+
u := "user/social_accounts"
52+
req, err := s.client.NewRequest("POST", u, accountURLs)
53+
if err != nil {
54+
return nil, nil, err
55+
}
56+
57+
var accounts []*SocialAccount
58+
resp, err := s.client.Do(ctx, req, &accounts)
59+
if err != nil {
60+
return nil, resp, err
61+
}
62+
63+
return accounts, resp, nil
64+
}
65+
66+
// DeleteSocialAccounts deletes social accounts for the authenticated user.
67+
//
68+
// GitHub API docs: https://docs.github.com/rest/users/social-accounts#delete-social-accounts-for-the-authenticated-user
69+
//
70+
//meta:operation DELETE /user/social_accounts
71+
func (s *UsersService) DeleteSocialAccounts(ctx context.Context, accountURLs []string) (*Response, error) {
72+
u := "user/social_accounts"
73+
req, err := s.client.NewRequest("DELETE", u, accountURLs)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
return s.client.Do(ctx, req, nil)
79+
}
80+
81+
// ListUserSocialAccounts lists all social accounts for a user.
82+
//
83+
// GitHub API docs: https://docs.github.com/rest/users/social-accounts#list-social-accounts-for-a-user
84+
//
85+
//meta:operation GET /users/{username}/social_accounts
86+
func (s *UsersService) ListUserSocialAccounts(ctx context.Context, username string, opts *ListOptions) ([]*SocialAccount, *Response, error) {
87+
u := fmt.Sprintf("users/%v/social_accounts", username)
88+
u, err := addOptions(u, opts)
89+
if err != nil {
90+
return nil, nil, err
91+
}
92+
93+
req, err := s.client.NewRequest("GET", u, nil)
94+
if err != nil {
95+
return nil, nil, err
96+
}
97+
98+
var addedAccounts []*SocialAccount
99+
resp, err := s.client.Do(ctx, req, &addedAccounts)
100+
if err != nil {
101+
return nil, resp, err
102+
}
103+
104+
return addedAccounts, resp, nil
105+
}

github/users_social_accounts_test.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright 2025 The go-github AUTHORS. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style
4+
// license that can be found in the LICENSE file.
5+
6+
package github
7+
8+
import (
9+
"context"
10+
"encoding/json"
11+
"fmt"
12+
"net/http"
13+
"testing"
14+
15+
"github.com/google/go-cmp/cmp"
16+
)
17+
18+
func TestUsersService_ListSocialAccounts(t *testing.T) {
19+
t.Parallel()
20+
21+
client, mux, _ := setup(t)
22+
23+
mux.HandleFunc("/user/social_accounts", func(w http.ResponseWriter, r *http.Request) {
24+
testMethod(t, r, "GET")
25+
testFormValues(t, r, values{"page": "2"})
26+
fmt.Fprint(w, `[{
27+
"provider": "twitter",
28+
"url": "https://twitter.com/github"
29+
}]`)
30+
})
31+
32+
opt := &ListOptions{Page: 2}
33+
ctx := context.Background()
34+
accounts, _, err := client.Users.ListSocialAccounts(ctx, opt)
35+
if err != nil {
36+
t.Errorf("Users.ListSocialAccounts returned error: %v", err)
37+
}
38+
39+
want := []*SocialAccount{{Provider: Ptr("twitter"), URL: Ptr("https://twitter.com/github")}}
40+
if !cmp.Equal(accounts, want) {
41+
t.Errorf("Users.ListSocialAccounts returned %#v, want %#v", accounts, want)
42+
}
43+
44+
const methodName = "ListSocialAccounts"
45+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
46+
got, resp, err := client.Users.ListSocialAccounts(ctx, opt)
47+
if got != nil {
48+
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
49+
}
50+
return resp, err
51+
})
52+
}
53+
54+
func TestUsersService_AddSocialAccounts(t *testing.T) {
55+
t.Parallel()
56+
57+
client, mux, _ := setup(t)
58+
59+
input := []string{"https://twitter.com/github"}
60+
61+
mux.HandleFunc("/user/social_accounts", func(w http.ResponseWriter, r *http.Request) {
62+
var v []string
63+
assertNilError(t, json.NewDecoder(r.Body).Decode(&v))
64+
65+
testMethod(t, r, "POST")
66+
if !cmp.Equal(v, input) {
67+
t.Errorf("Request body = %+v, want %+v", v, input)
68+
}
69+
70+
fmt.Fprint(w, `[{"provider":"twitter","url":"https://twitter.com/github"},{"provider":"facebook","url":"https://facebook.com/github"}]`)
71+
})
72+
73+
ctx := context.Background()
74+
accounts, _, err := client.Users.AddSocialAccounts(ctx, input)
75+
if err != nil {
76+
t.Errorf("Users.AddSocialAccounts returned error: %v", err)
77+
}
78+
79+
want := []*SocialAccount{
80+
{Provider: Ptr("twitter"), URL: Ptr("https://twitter.com/github")},
81+
{Provider: Ptr("facebook"), URL: Ptr("https://facebook.com/github")},
82+
}
83+
if !cmp.Equal(accounts, want) {
84+
t.Errorf("Users.AddSocialAccounts returned %#v, want %#v", accounts, want)
85+
}
86+
87+
const methodName = "AddSocialAccounts"
88+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
89+
got, resp, err := client.Users.AddSocialAccounts(ctx, input)
90+
if got != nil {
91+
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
92+
}
93+
return resp, err
94+
})
95+
}
96+
97+
func TestUsersService_DeleteSocialAccounts(t *testing.T) {
98+
t.Parallel()
99+
100+
client, mux, _ := setup(t)
101+
102+
input := []string{"https://twitter.com/github"}
103+
104+
mux.HandleFunc("/user/social_accounts", func(_ http.ResponseWriter, r *http.Request) {
105+
var v []string
106+
assertNilError(t, json.NewDecoder(r.Body).Decode(&v))
107+
108+
testMethod(t, r, "DELETE")
109+
if !cmp.Equal(v, input) {
110+
t.Errorf("Request body = %+v, want %+v", v, input)
111+
}
112+
})
113+
114+
ctx := context.Background()
115+
_, err := client.Users.DeleteSocialAccounts(ctx, input)
116+
if err != nil {
117+
t.Errorf("Users.DeleteSocialAccounts returned error: %v", err)
118+
}
119+
120+
const methodName = "DeleteSocialAccounts"
121+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
122+
return client.Users.DeleteSocialAccounts(ctx, input)
123+
})
124+
}
125+
126+
func TestUsersService_ListUserSocialAccounts(t *testing.T) {
127+
t.Parallel()
128+
129+
client, mux, _ := setup(t)
130+
131+
mux.HandleFunc("/users/u/social_accounts", func(w http.ResponseWriter, r *http.Request) {
132+
testMethod(t, r, "GET")
133+
testFormValues(t, r, values{"page": "2"})
134+
fmt.Fprint(w, `[{
135+
"provider": "twitter",
136+
"url": "https://twitter.com/github"
137+
}]`)
138+
})
139+
140+
opt := &ListOptions{Page: 2}
141+
ctx := context.Background()
142+
accounts, _, err := client.Users.ListUserSocialAccounts(ctx, "u", opt)
143+
if err != nil {
144+
t.Errorf("Users.ListUserSocialAccounts returned error: %v", err)
145+
}
146+
147+
want := []*SocialAccount{{Provider: Ptr("twitter"), URL: Ptr("https://twitter.com/github")}}
148+
if !cmp.Equal(accounts, want) {
149+
t.Errorf("Users.ListUserSocialAccounts returned %#v, want %#v", accounts, want)
150+
}
151+
152+
const methodName = "ListUserSocialAccounts"
153+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
154+
got, resp, err := client.Users.ListUserSocialAccounts(ctx, "u", opt)
155+
if got != nil {
156+
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
157+
}
158+
return resp, err
159+
})
160+
}

0 commit comments

Comments
 (0)