diff --git a/src/api/handlers/account/github.py b/src/api/handlers/account/github.py index 63e22cb67..b19734e34 100644 --- a/src/api/handlers/account/github.py +++ b/src/api/handlers/account/github.py @@ -1,5 +1,6 @@ import uuid import os +import re import requests from flask import g, request, abort, redirect @@ -42,7 +43,14 @@ def get_next_page(r): n3 = link.find('>;', n2) return link[n2:n3] -def get_github_api(url, token): +def parse_link_header(link): + reg = r"<.+?page=(?P\d+)>; rel=\"(?Pprev|next|first|last)\"" + res = {} + for match in re.finditer(reg, link): + res[match.group("direction")] = match.group("page") + return res + +def get_github_api(url, token, raw_result=False): headers = { "Authorization": "token " + token, "User-Agent": "InfraBox" @@ -51,6 +59,8 @@ def get_github_api(url, token): # TODO(ib-steffen): allow custom ca bundles r = requests.get(url, headers=headers, verify=False) + if raw_result: + return r result = [] result.extend(r.json()) @@ -126,6 +136,49 @@ def get(self): return github_repos +@api.route('/api/v1/github/paginated_repos', doc=False) +class V2Repos(Resource): + + def get(self): + user_id = g.token['user']['id'] + + user = g.db.execute_one_dict(''' + SELECT github_api_token + FROM "user" + WHERE id = %s + ''', [user_id]) + + if not user: + abort(404) + + token = user['github_api_token'] + + page = request.args.get('page', 1) + per_page = request.args.get('per_page', 50) + github_repos_response = get_github_api('/user/repos?visibility=all&page={page}&per_page={per_page}' + .format(page=page, per_page=per_page), + token, raw_result=True) + github_repos = github_repos_response.json() + filtered_repos = [] + for github_repo in github_repos: + filtered_repos.append({ + "name": github_repo["name"], + "owner_login": github_repo["owner"]["login"], + "private": github_repo["private"], + "open_issues_count": github_repo["open_issues_count"], + "forks_count": github_repo["forks_count"], + }) + + nav = {} + for direction, page in parse_link_header(github_repos_response.headers.get('Link', "")).items(): + nav[direction] = page + result = { + "nav": nav, + "items": filtered_repos + } + return result + + @api.route('/github/auth', doc=False) class Auth(Resource): diff --git a/src/dashboard-client/src/components/AddProject.vue b/src/dashboard-client/src/components/AddProject.vue index d360b9923..7cf74b873 100644 --- a/src/dashboard-client/src/components/AddProject.vue +++ b/src/dashboard-client/src/components/AddProject.vue @@ -9,7 +9,7 @@ - +

Select project type

@@ -56,9 +56,9 @@ - + {{ r.name }} - {{ r.owner.login }} + {{ r.owner_login }} @@ -72,6 +72,13 @@ +
@@ -99,10 +106,14 @@ import ProjectService from '../services/ProjectService' import UserService from '../services/UserService' import store from '../store' +import ApiTablePagination from './utils/ApiTablePagination' export default { name: 'AddProject', store, + components: { + 'ib-api-table-pagination': ApiTablePagination + }, data: () => ({ projName: '', nameValid: false, @@ -110,11 +121,10 @@ export default { priv: true, githubRepo: null, invalidMessage: 'Name required', - selectRepo: false + selectRepo: false, + page: 1, + size: 50 }), - created () { - UserService.loadRepos() - }, watch: { projName () { if (this.projName.length < 3) { @@ -141,11 +151,20 @@ export default { ProjectService.addProject(this.projName, this.priv, this.type, repoName) }, + stepperChange (value) { + if (value === 1 && this.type === 'github') { + UserService.loadRepos(1, this.size) + } + }, selectGithubRepo (r) { this.githubRepo = r }, connectGithubAccount () { window.location.href = '/github/auth/connect' + }, + onPagination (page) { + UserService.loadRepos(page, this.size) + this.page = parseInt(page) } } } diff --git a/src/dashboard-client/src/components/utils/ApiTablePagination.vue b/src/dashboard-client/src/components/utils/ApiTablePagination.vue new file mode 100644 index 000000000..fa0ec8092 --- /dev/null +++ b/src/dashboard-client/src/components/utils/ApiTablePagination.vue @@ -0,0 +1,89 @@ + + + \ No newline at end of file diff --git a/src/dashboard-client/src/services/UserService.js b/src/dashboard-client/src/services/UserService.js index 0813c2c3c..52087dbbe 100644 --- a/src/dashboard-client/src/services/UserService.js +++ b/src/dashboard-client/src/services/UserService.js @@ -70,9 +70,9 @@ class UserService { }) } - loadRepos () { + loadRepos (page, perPage) { if (store.state.user.hasGithubAccount() && store.state.settings.INFRABOX_GITHUB_ENABLED) { - return NewAPIService.get('github/repos/') + return NewAPIService.get('github/paginated_repos?page=' + page + '&per_page=' + perPage) .then((d) => { if (d) { store.commit('setGithubRepos', d) diff --git a/src/openpolicyagent/policies/github.rego b/src/openpolicyagent/policies/github.rego index 999016184..b32b066a9 100644 --- a/src/openpolicyagent/policies/github.rego +++ b/src/openpolicyagent/policies/github.rego @@ -19,6 +19,12 @@ allow { api.token.type = "user" } +allow { + api.method = "GET" + api.path = ["api", "v1", "github", "paginated_repos"] + api.token.type = "user" +} + allow { api.method = "GET" api.path = ["github", "auth"]