mirror of https://github.com/gogs/gogs.git
171 lines
4.7 KiB
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)
|
|
}
|