gogs/routes/api/srcgraph/general_protocol.go

171 lines
4.7 KiB
Go

// Copyright 2019 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package srcgraph
import (
"net/http"
"time"
"github.com/Unknwon/com"
adapter "github.com/sourcegraph/external-service-adapter"
log "gopkg.in/clog.v1"
"github.com/gogs/gogs/models"
"github.com/gogs/gogs/models/errors"
"github.com/gogs/gogs/pkg/setting"
)
func NewHandler() http.HandlerFunc {
h := adapter.NewHandler(externalServicer{}, adapter.Options{
URL: setting.AppURL,
PathPrefix: "/-/srcgraph",
MaxPageLen: 100000, // Current version returns all repositories at once, does not matter
})
return h.ServeHTTP
}
type externalServicer struct{}
func (es externalServicer) ListRepos(ai adapter.AuthInfo, params adapter.Params) ([]*adapter.Repo, adapter.Page, error) {
return es.listUserRepos("", ai, params)
}
func (es externalServicer) ListUserRepos(user string, ai adapter.AuthInfo, params adapter.Params) ([]*adapter.Repo, adapter.Page, error) {
return es.listUserRepos(user, ai, params)
}
func toRepo(r *models.Repository) *adapter.Repo {
var parent *adapter.Repo
if r.IsFork {
parent = toRepo(r.BaseRepo)
}
cl := r.CloneLink()
return &adapter.Repo{
ID: com.ToStr(r.ID),
Name: r.Name,
Slug: r.Name,
FullName: r.FullName(),
SCM: "git",
Description: r.Description,
IsPrivate: r.IsPrivate,
Parent: parent,
Links: []adapter.Link{
{adapter.CloneSSH, cl.SSH},
{adapter.CloneHTTP, cl.HTTPS},
},
}
}
func (es externalServicer) listUserRepos(username string, ai adapter.AuthInfo, params adapter.Params) ([]*adapter.Repo, adapter.Page, error) {
authUser, err := userFromAuthInfo(ai)
if err != nil {
if errors.IsUserNotExist(err) {
return nil, adapter.Page{}, errors.New("403 Forbidden")
}
log.Error(2, "Failed to get user from auth info: %v", err)
return nil, adapter.Page{}, errors.New("500 Internal Server Error")
}
// Fall back to authenticated user
if username == "" {
username = authUser.Name
}
user, err := models.GetUserByName(username)
if err != nil {
if errors.IsUserNotExist(err) {
return nil, adapter.Page{}, errors.New("404 Not Found")
}
log.Error(2, "Failed to get user by username %q: %v", username, err)
return nil, adapter.Page{}, errors.New("500 Internal Server Error")
}
// Only list public repositories if user requests someone else's repository list,
// or an organization isn't a member of.
var ownRepos []*models.Repository
if user.IsOrganization() {
ownRepos, _, err = user.GetUserRepositories(authUser.ID, params.Page, user.NumRepos)
} else {
ownRepos, err = models.GetUserRepositories(&models.UserRepoOptions{
UserID: user.ID,
Private: authUser.ID == user.ID,
Page: params.Page,
PageSize: user.NumRepos,
})
}
if err != nil {
log.Error(2, "Failed to get repositories of user %q: %v", username, err)
return nil, adapter.Page{}, errors.New("500 Internal Server Error")
}
if err = models.RepositoryList(ownRepos).LoadAttributes(); err != nil {
log.Error(2, "Failed to load attributes of repositories: %v", err)
return nil, adapter.Page{}, errors.New("500 Internal Server Error")
}
// Early return for querying other user's repositories
if authUser.ID != user.ID {
repos := make([]*adapter.Repo, len(ownRepos))
for i := range ownRepos {
repos[i] = toRepo(ownRepos[i])
}
return repos, adapter.Page{Last: 1}, nil
}
accessibleRepos, err := user.GetRepositoryAccesses()
if err != nil {
log.Error(2, "Failed to get accessible repositories of user %q: %v", username, err)
return nil, adapter.Page{}, errors.New("500 Internal Server Error")
}
numOwnRepos := len(ownRepos)
repos := make([]*adapter.Repo, numOwnRepos+len(accessibleRepos))
for i := range ownRepos {
repos[i] = toRepo(ownRepos[i])
}
i := numOwnRepos
for repo := range accessibleRepos {
repos[i] = toRepo(repo)
i++
}
return repos, adapter.Page{Last: 1}, nil
}
func userFromAuthInfo(ai adapter.AuthInfo) (*models.User, error) {
if ai.Method == adapter.AuthBasic {
u, err := models.UserLogin(ai.Username, ai.Password, -1)
if err != nil {
return nil, err
}
if u.IsEnabledTwoFactor() {
return nil, errors.New(
"User with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password." +
" Please create and use personal access token on user settings page.")
}
return u, nil
}
t, err := models.GetAccessTokenBySHA(ai.Token)
if err != nil {
if models.IsErrAccessTokenEmpty(err) || models.IsErrAccessTokenNotExist(err) {
return nil, errors.UserNotExist{}
}
return nil, err
}
t.Updated = time.Now()
u, err := models.GetUserByID(t.UID)
if err != nil {
return nil, err
}
return u, models.UpdateAccessToken(t)
}