@@ -7,6 +7,7 @@ import (
77 "net/http"
88 "net/url"
99 "path"
10+ "regexp"
1011 "strconv"
1112 "strings"
1213
@@ -75,8 +76,8 @@ func (p *GitHubProvider) hasOrg(accessToken string) (bool, error) {
7576 pn := 1
7677 for {
7778 params := url.Values{
78− "limit": {"200"},
79− "page": {strconv.Itoa(pn)},
79+ "per_page": {"100"},
80+ "page": {strconv.Itoa(pn)},
8081 }
8182
8283 endpoint := &url.URL{
@@ -139,36 +140,90 @@ func (p *GitHubProvider) hasOrgAndTeam(accessToken string) (bool, error) {
139140 } `json:"organization"`
140141 }
141142
142− params := url.Values{
143− "limit": {"200"},
143+ type teamsPage []struct {
144+ Name string `json:"name"`
145+ Slug string `json:"slug"`
146+ Org struct {
147+ Login string `json:"login"`
148+ } `json:"organization"`
144149 }
145150
146− endpoint := &url.URL{
147− Scheme: p.ValidateURL.Scheme,
148− Host: p.ValidateURL.Host,
149− Path: path.Join(p.ValidateURL.Path, "/user/teams"),
150− RawQuery: params.Encode(),
151− }
152− req, _ := http.NewRequest("GET", endpoint.String(), nil)
153− req.Header.Set("Accept", "application/vnd.github.v3+json")
154− req.Header.Set("Authorization", fmt.Sprintf("token %s", accessToken))
155− resp, err := http.DefaultClient.Do(req)
156− if err != nil {
157− return false, err
158− }
151+ pn := 1
152+ last := 0
153+ for {
154+ params := url.Values{
155+ "per_page": {"100"},
156+ "page": {strconv.Itoa(pn)},
157+ }
159158
160− body, err := ioutil.ReadAll(resp.Body)
161− resp.Body.Close()
162− if err != nil {
163− return false, err
164− }
165− if resp.StatusCode != 200 {
166− return false, fmt.Errorf(
167− "got %d from %q %s", resp.StatusCode, endpoint.String(), body)
168− }
159+ endpoint := &url.URL{
160+ Scheme: p.ValidateURL.Scheme,
161+ Host: p.ValidateURL.Host,
162+ Path: path.Join(p.ValidateURL.Path, "/user/teams"),
163+ RawQuery: params.Encode(),
164+ }
169165
170− if err := json.Unmarshal(body, &teams); err != nil {
171− return false, fmt.Errorf("%s unmarshaling %s", err, body)
166+ req, _ := http.NewRequest("GET", endpoint.String(), nil)
167+ req.Header.Set("Accept", "application/vnd.github.v3+json")
168+ req.Header.Set("Authorization", fmt.Sprintf("token %s", accessToken))
169+ resp, err := http.DefaultClient.Do(req)
170+ if err != nil {
171+ return false, err
172+ }
173+
174+ if last == 0 {
175+ // link header may not be obtained
176+ // When paging is not required and all data can be retrieved with a single call
177+
178+ // Conditions for obtaining the link header.
179+ // 1. When paging is required (Example: When the data size is 100 and the page size is 99 or less)
180+ // 2. When it exceeds the paging frame (Example: When there is only 10 records but the second page is called with a page size of 100)
181+
182+ // link header at not last page
183+ // <https://api.github.com/user/teams?page=1&per_page=100>; rel="prev", <https://api.github.com/user/teams?page=1&per_page=100>; rel="last", <https://api.github.com/user/teams?page=1&per_page=100>; rel="first"
184+ // link header at last page (doesn't exist last info)
185+ // <https://api.github.com/user/teams?page=3&per_page=10>; rel="prev", <https://api.github.com/user/teams?page=1&per_page=10>; rel="first"
186+
187+ link := resp.Header.Get("Link")
188+ rep1 := regexp.MustCompile(`(?s).*\<https://api.github.com/user/teams\?page=(.)&per_page=[0-9]+\>; rel="last".*`)
189+ i, converr := strconv.Atoi(rep1.ReplaceAllString(link, "$1"))
190+
191+ // If the last page cannot be taken from the link in the http header, the last variable remains zero
192+ if converr == nil {
193+ last = i
194+ }
195+ }
196+
197+ body, err := ioutil.ReadAll(resp.Body)
198+ if err != nil {
199+ resp.Body.Close()
200+ return false, err
201+ }
202+ resp.Body.Close()
203+
204+ if resp.StatusCode != 200 {
205+ return false, fmt.Errorf(
206+ "got %d from %q %s", resp.StatusCode, endpoint.String(), body)
207+ }
208+
209+ var tp teamsPage
210+ if err := json.Unmarshal(body, &tp); err != nil {
211+ return false, fmt.Errorf("%s unmarshaling %s", err, body)
212+ }
213+ if len(tp) == 0 {
214+ break
215+ }
216+
217+ teams = append(teams, tp...)
218+
219+ if pn == last {
220+ break
221+ }
222+ if last == 0 {
223+ break
224+ }
225+
226+ pn++
172227 }
173228
174229 var hasOrg bool