woodpecker/pkg/handler/repos.go
2014-02-12 12:22:56 -07:00

287 lines
7 KiB
Go

package handler
import (
"fmt"
"log"
"net/http"
"github.com/drone/drone/pkg/channel"
"github.com/drone/drone/pkg/database"
. "github.com/drone/drone/pkg/model"
"github.com/drone/go-github/github"
"launchpad.net/goyaml"
)
// Display a Repository dashboard.
func RepoDashboard(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
branch := r.FormValue("branch")
// get a list of all branches
branches, err := database.ListBranches(repo.ID)
if err != nil {
return err
}
// if no branch is provided then we'll
// want to use a default value.
if len(branch) == 0 {
branch = repo.DefaultBranch()
}
// get a list of recent commits for the
// repository and specific branch
commits, err := database.ListCommits(repo.ID, branch)
if err != nil {
return err
}
// get a token that can be exchanged with the
// websocket handler to authorize listening
// for a stream of changes for this repository
token := channel.Create(repo.Slug)
data := struct {
User *User
Repo *Repo
Branches []*Commit
Commits []*Commit
Branch string
Token string
}{u, repo, branches, commits, branch, token}
return RenderTemplate(w, "repo_dashboard.html", &data)
}
func RepoAdd(w http.ResponseWriter, r *http.Request, u *User) error {
teams, err := database.ListTeams(u.ID)
if err != nil {
return err
}
data := struct {
User *User
Teams []*Team
}{u, teams}
// if the user hasn't linked their GitHub account
// render a different template
if len(u.GithubToken) == 0 {
return RenderTemplate(w, "github_link.html", &data)
}
// otherwise display the template for adding
// a new GitHub repository.
return RenderTemplate(w, "github_add.html", &data)
}
func RepoCreateGithub(w http.ResponseWriter, r *http.Request, u *User) error {
teamName := r.FormValue("team")
owner := r.FormValue("owner")
name := r.FormValue("name")
// get the github settings from the database
settings := database.SettingsMust()
// create the GitHub client
client := github.New(u.GithubToken)
githubRepo, err := client.Repos.Find(owner, name)
if err != nil {
return err
}
repo, err := NewGitHubRepo(owner, name, githubRepo.Private)
if err != nil {
return err
}
repo.UserID = u.ID
repo.Private = githubRepo.Private
// if the user chose to assign to a team account
// we need to retrieve the team, verify the user
// has access, and then set the team id.
if len(teamName) > 0 {
team, err := database.GetTeamSlug(teamName)
if err != nil {
log.Printf("error retrieving team %s", teamName)
return err
}
// user must be an admin member of the team
if ok, _ := database.IsMemberAdmin(u.ID, team.ID); !ok {
return fmt.Errorf("Forbidden")
}
repo.TeamID = team.ID
}
// if the repository is private we'll need
// to upload a github key to the repository
if repo.Private {
// name the key
keyName := fmt.Sprintf("%s@%s", repo.Owner, settings.Domain)
// create the github key, or update if one already exists
_, err := client.RepoKeys.CreateUpdate(owner, name, repo.PublicKey, keyName)
if err != nil {
return fmt.Errorf("Unable to add Private Key to your GitHub repository")
}
} else {
}
// create a hook so that we get notified when code
// is pushed to the repository and can execute a build.
link := fmt.Sprintf("%s://%s/hook/github.com?id=%s", settings.Scheme, settings.Domain, repo.Slug)
// add the hook
if _, err := client.Hooks.CreateUpdate(owner, name, link); err != nil {
return fmt.Errorf("Unable to add Hook to your GitHub repository. %s", err.Error())
}
// Save to the database
if err := database.SaveRepo(repo); err != nil {
log.Print("error saving new repository to the database")
return err
}
return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)
}
// Repository Settings
func RepoSettingsForm(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
// get the list of teams
teams, err := database.ListTeams(u.ID)
if err != nil {
return err
}
data := struct {
Repo *Repo
User *User
Teams []*Team
Owner *User
Team *Team
}{Repo: repo, User: u, Teams: teams}
// get the repo owner
if repo.TeamID > 0 {
data.Team, err = database.GetTeam(repo.TeamID)
if err != nil {
return err
}
}
// get the team owner
data.Owner, err = database.GetUser(repo.UserID)
if err != nil {
return err
}
return RenderTemplate(w, "repo_settings.html", &data)
}
// Repository Params (YAML parameters) Form
func RepoParamsForm(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
data := struct {
Repo *Repo
User *User
Textarea string
}{repo, u, ""}
if repo.Params != nil && len(repo.Params) != 0 {
raw, _ := goyaml.Marshal(&repo.Params)
data.Textarea = string(raw)
}
return RenderTemplate(w, "repo_params.html", &data)
}
func RepoBadges(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
// hostname from settings
hostname := database.SettingsMust().URL().String()
data := struct {
Repo *Repo
User *User
Host string
}{repo, u, hostname}
return RenderTemplate(w, "repo_badges.html", &data)
}
func RepoKeys(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
data := struct {
Repo *Repo
User *User
}{repo, u}
return RenderTemplate(w, "repo_keys.html", &data)
}
// Updates an existing repository.
func RepoUpdate(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
switch r.FormValue("action") {
case "params":
repo.Params = map[string]string{}
if err := goyaml.Unmarshal([]byte(r.FormValue("params")), &repo.Params); err != nil {
return err
}
default:
repo.Disabled = len(r.FormValue("Disabled")) == 0
repo.DisabledPullRequest = len(r.FormValue("DisabledPullRequest")) == 0
// value of "" indicates the currently authenticated user
// should be set as the administrator.
if len(r.FormValue("Owner")) == 0 {
repo.UserID = u.ID
repo.TeamID = 0
} else {
// else the user has chosen a team
team, err := database.GetTeamSlug(r.FormValue("Owner"))
if err != nil {
return err
}
// verify the user is a member of the team
if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member {
return fmt.Errorf("Forbidden")
}
// set the team ID
repo.TeamID = team.ID
}
}
// save the page
if err := database.SaveRepo(repo); err != nil {
return err
}
http.Redirect(w, r, r.URL.Path, http.StatusSeeOther)
return nil
}
// Deletes a specific repository.
func RepoDeleteForm(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
data := struct {
Repo *Repo
User *User
}{repo, u}
return RenderTemplate(w, "repo_delete.html", &data)
}
// Deletes a specific repository.
func RepoDelete(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
// the user must confirm their password before deleting
password := r.FormValue("password")
if err := u.ComparePassword(password); err != nil {
return RenderError(w, err, http.StatusBadRequest)
}
// delete the repo
if err := database.DeleteRepo(repo.ID); err != nil {
return err
}
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
return nil
}