302 lines
7.8 KiB
Go
302 lines
7.8 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/drone/drone/plugin/remote"
|
|
"github.com/drone/drone/server/database"
|
|
"github.com/drone/drone/server/session"
|
|
"github.com/drone/drone/shared/httputil"
|
|
"github.com/drone/drone/shared/model"
|
|
"github.com/drone/drone/shared/sshutil"
|
|
"github.com/gorilla/pat"
|
|
)
|
|
|
|
type RepoHandler struct {
|
|
remotes database.RemoteManager
|
|
commits database.CommitManager
|
|
perms database.PermManager
|
|
repos database.RepoManager
|
|
sess session.Session
|
|
}
|
|
|
|
func NewRepoHandler(repos database.RepoManager, commits database.CommitManager,
|
|
perms database.PermManager, sess session.Session, remotes database.RemoteManager) *RepoHandler {
|
|
return &RepoHandler{remotes, commits, perms, repos, sess}
|
|
}
|
|
|
|
// GetRepo gets the named repository.
|
|
// GET /v1/repos/:host/:owner/:name
|
|
func (h *RepoHandler) GetRepo(w http.ResponseWriter, r *http.Request) error {
|
|
var host, owner, name = parseRepo(r)
|
|
var admin = r.FormValue("admin")
|
|
|
|
// get the user form the session.
|
|
user := h.sess.User(r)
|
|
|
|
// get the repository from the database.
|
|
repo, err := h.repos.FindName(host, owner, name)
|
|
switch {
|
|
case err != nil && user == nil:
|
|
return notAuthorized{}
|
|
case err != nil && user != nil:
|
|
return notFound{}
|
|
}
|
|
|
|
// user must have read access to the repository.
|
|
role := h.perms.Find(user, repo)
|
|
switch {
|
|
case role.Read == false && user == nil:
|
|
return notAuthorized{}
|
|
case role.Read == false && user != nil:
|
|
return notFound{}
|
|
}
|
|
// if the user is not requesting admin data we can
|
|
// return exactly what we have.
|
|
if len(admin) == 0 {
|
|
return json.NewEncoder(w).Encode(struct {
|
|
*model.Repo
|
|
Role *model.Perm `json:"role"`
|
|
}{repo, role})
|
|
}
|
|
|
|
// ammend the response to include data that otherwise
|
|
// would be excluded from json serialization, assuming
|
|
// the user is actually an admin of the repo.
|
|
if ok, _ := h.perms.Admin(user, repo); !ok {
|
|
return notFound{err}
|
|
}
|
|
|
|
return json.NewEncoder(w).Encode(struct {
|
|
*model.Repo
|
|
Role *model.Perm `json:"role"`
|
|
PublicKey string `json:"public_key"`
|
|
Params string `json:"params"`
|
|
}{repo, role, repo.PublicKey, repo.Params})
|
|
}
|
|
|
|
// PostRepo activates the named repository.
|
|
// POST /v1/repos/:host/:owner/:name
|
|
func (h *RepoHandler) PostRepo(w http.ResponseWriter, r *http.Request) error {
|
|
var host, owner, name = parseRepo(r)
|
|
|
|
// get the user form the session.
|
|
user := h.sess.User(r)
|
|
if user == nil {
|
|
return notAuthorized{}
|
|
}
|
|
|
|
// get the repo from the database
|
|
repo, err := h.repos.FindName(host, owner, name)
|
|
switch {
|
|
case err != nil && user == nil:
|
|
return notAuthorized{}
|
|
case err != nil && user != nil:
|
|
return notFound{}
|
|
}
|
|
|
|
// user must have admin access to the repository.
|
|
if ok, _ := h.perms.Admin(user, repo); !ok {
|
|
return notFound{err}
|
|
}
|
|
|
|
// update the repo active flag and fields
|
|
repo.Active = true
|
|
repo.PullRequest = true
|
|
repo.PostCommit = true
|
|
repo.UserID = user.ID
|
|
|
|
// generate the rsa key
|
|
key, err := sshutil.GeneratePrivateKey()
|
|
if err != nil {
|
|
return internalServerError{err}
|
|
}
|
|
|
|
// marshal the public and private key values
|
|
repo.PublicKey = sshutil.MarshalPublicKey(&key.PublicKey)
|
|
repo.PrivateKey = sshutil.MarshalPrivateKey(key)
|
|
|
|
// get the remote and client
|
|
remoteServer, err := h.remotes.FindType(repo.Remote)
|
|
if err != nil {
|
|
return notFound{err}
|
|
}
|
|
|
|
remotePlugin, ok := remote.Lookup(remoteServer.Type)
|
|
if !ok {
|
|
return notFound{}
|
|
}
|
|
|
|
// get the remote system's client.
|
|
plugin := remotePlugin(remoteServer)
|
|
|
|
// post commit hook url
|
|
hook := fmt.Sprintf("%s://%s/v1/hook/%s", httputil.GetScheme(r), httputil.GetHost(r), plugin.GetName())
|
|
|
|
// activate the repository in the remote system
|
|
client := plugin.GetClient(user.Access, user.Secret)
|
|
if err := client.SetActive(owner, name, hook, repo.PublicKey); err != nil {
|
|
return badRequest{err}
|
|
}
|
|
|
|
// update the status in the database
|
|
if err := h.repos.Update(repo); err != nil {
|
|
return badRequest{err}
|
|
}
|
|
|
|
w.WriteHeader(http.StatusCreated)
|
|
return json.NewEncoder(w).Encode(repo)
|
|
}
|
|
|
|
// PutRepo updates the named repository.
|
|
// PUT /v1/repos/:host/:owner/:name
|
|
func (h *RepoHandler) PutRepo(w http.ResponseWriter, r *http.Request) error {
|
|
var host, owner, name = parseRepo(r)
|
|
|
|
// get the user form the session.
|
|
user := h.sess.User(r)
|
|
if user == nil {
|
|
return notAuthorized{}
|
|
}
|
|
|
|
// get the repo from the database
|
|
repo, err := h.repos.FindName(host, owner, name)
|
|
switch {
|
|
case err != nil && user == nil:
|
|
return notAuthorized{}
|
|
case err != nil && user != nil:
|
|
return notFound{}
|
|
}
|
|
|
|
// user must have admin access to the repository.
|
|
if ok, _ := h.perms.Admin(user, repo); !ok {
|
|
return notFound{err}
|
|
}
|
|
|
|
// unmarshal the repository from the payload
|
|
defer r.Body.Close()
|
|
in := struct {
|
|
PostCommit *bool `json:"post_commits"`
|
|
PullRequest *bool `json:"pull_requests"`
|
|
Privileged *bool `json:"privileged"`
|
|
Params *string `json:"params"`
|
|
Timeout *int64 `json:"timeout"`
|
|
}{}
|
|
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
|
|
return badRequest{err}
|
|
}
|
|
|
|
// update the private/secure parameters
|
|
if in.Params != nil {
|
|
repo.Params = *in.Params
|
|
}
|
|
// update the post commit flag
|
|
if in.PostCommit != nil {
|
|
repo.PostCommit = *in.PostCommit
|
|
}
|
|
// update the pull request flag
|
|
if in.PullRequest != nil {
|
|
repo.PullRequest = *in.PullRequest
|
|
}
|
|
// update the privileged flag. This can only be updated by
|
|
// the system administrator
|
|
if in.Privileged != nil && user.Admin {
|
|
repo.Privileged = *in.Privileged
|
|
}
|
|
// update the timeout. This can only be updated by
|
|
// the system administrator
|
|
if in.Timeout != nil && user.Admin {
|
|
repo.Timeout = *in.Timeout
|
|
}
|
|
|
|
// update the repository
|
|
if err := h.repos.Update(repo); err != nil {
|
|
return badRequest{err}
|
|
}
|
|
|
|
return json.NewEncoder(w).Encode(repo)
|
|
}
|
|
|
|
// DeleteRepo deletes the named repository.
|
|
// DEL /v1/repos/:host/:owner/:name
|
|
func (h *RepoHandler) DeleteRepo(w http.ResponseWriter, r *http.Request) error {
|
|
var host, owner, name = parseRepo(r)
|
|
|
|
// get the user form the session.
|
|
user := h.sess.User(r)
|
|
if user == nil {
|
|
return notAuthorized{}
|
|
}
|
|
|
|
// get the repo from the database
|
|
repo, err := h.repos.FindName(host, owner, name)
|
|
switch {
|
|
case err != nil && user == nil:
|
|
return notAuthorized{}
|
|
case err != nil && user != nil:
|
|
return notFound{}
|
|
}
|
|
|
|
// user must have admin access to the repository.
|
|
if ok, _ := h.perms.Admin(user, repo); !ok {
|
|
return notFound{err}
|
|
}
|
|
|
|
// update the repo active flag and fields.
|
|
repo.Active = false
|
|
repo.PullRequest = false
|
|
repo.PostCommit = false
|
|
|
|
// insert the new repository
|
|
if err := h.repos.Update(repo); err != nil {
|
|
return badRequest{err}
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return nil
|
|
}
|
|
|
|
// GetFeed gets the most recent commits across all branches
|
|
// GET /v1/repos/{host}/{owner}/{name}/feed
|
|
func (h *RepoHandler) GetFeed(w http.ResponseWriter, r *http.Request) error {
|
|
var host, owner, name = parseRepo(r)
|
|
|
|
// get the user form the session.
|
|
user := h.sess.User(r)
|
|
|
|
// get the repository from the database.
|
|
repo, err := h.repos.FindName(host, owner, name)
|
|
switch {
|
|
case err != nil && user == nil:
|
|
return notAuthorized{}
|
|
case err != nil && user != nil:
|
|
return notFound{}
|
|
}
|
|
|
|
// user must have read access to the repository.
|
|
ok, _ := h.perms.Read(user, repo)
|
|
switch {
|
|
case ok == false && user == nil:
|
|
return notAuthorized{}
|
|
case ok == false && user != nil:
|
|
return notFound{}
|
|
}
|
|
|
|
// lists the most recent commits across all branches.
|
|
commits, err := h.commits.List(repo.ID)
|
|
if err != nil {
|
|
return notFound{err}
|
|
}
|
|
|
|
return json.NewEncoder(w).Encode(commits)
|
|
}
|
|
|
|
func (h *RepoHandler) Register(r *pat.Router) {
|
|
r.Get("/v1/repos/{host}/{owner}/{name}/feed", errorHandler(h.GetFeed))
|
|
r.Get("/v1/repos/{host}/{owner}/{name}", errorHandler(h.GetRepo))
|
|
r.Put("/v1/repos/{host}/{owner}/{name}", errorHandler(h.PutRepo))
|
|
r.Post("/v1/repos/{host}/{owner}/{name}", errorHandler(h.PostRepo))
|
|
r.Delete("/v1/repos/{host}/{owner}/{name}", errorHandler(h.DeleteRepo))
|
|
}
|