internal/httpd/settings.go

6b2b26db548cdb89367154ba6ff4b0bcce21dd67
gitbay/internal/httpd/settings.go history · blame · raw

115 lines · 3456 bytes

  1package httpd
  2
  3import (
  4	"fmt"
  5	"net/http"
  6	"net/url"
  7	"strings"
  8
  9	"gitbay.org/gitbay/internal/gitutil"
 10	"gitbay.org/gitbay/internal/store"
 11)
 12
 13// Repository settings for repo admins. Every control dispatches the
 14// command the CLI runs; the page only groups them. Destructive lifecycle
 15// — delete and transfer — stays on the CLI, where a typed confirmation
 16// is the norm.
 17
 18type settingsPage struct {
 19	repoPage
 20	Topics   []string
 21	Branches []gitutil.Ref
 22	Notice   string
 23}
 24
 25func (s *Server) settingsForm(w http.ResponseWriter, r *http.Request, u store.User) {
 26	repo, ok := s.repoForUser(w, r, u, policyCanAdmin)
 27	if !ok {
 28		return
 29	}
 30	p, ok := s.repoFor(w, r, "")
 31	if !ok {
 32		return
 33	}
 34	p.Tab = "settings"
 35	topics, _ := s.st.ListTopics(repo.ID)
 36	branches, _ := gitutil.Refs(p.Dir, "heads")
 37	s.render(w, "settings.html", settingsPage{
 38		repoPage: p, Topics: topics, Branches: branches,
 39		Notice: r.URL.Query().Get("e"),
 40	})
 41}
 42
 43func (s *Server) settingsRedirect(w http.ResponseWriter, r *http.Request, msg string) {
 44	dest := fmt.Sprintf("/%s/%s/settings", r.PathValue("owner"), r.PathValue("repo"))
 45	if msg != "" {
 46		if len(msg) > 300 {
 47			msg = msg[:300]
 48		}
 49		dest += "?e=" + url.QueryEscape(msg)
 50	}
 51	http.Redirect(w, r, dest, http.StatusSeeOther)
 52}
 53
 54// settingsSubmit routes one form to its command. Keeping the mapping in
 55// one place makes what the page can reach obvious.
 56func (s *Server) settingsSubmit(w http.ResponseWriter, r *http.Request, u store.User) {
 57	repo := r.PathValue("owner") + "/" + r.PathValue("repo")
 58	v := func(k string) string { return strings.TrimSpace(r.FormValue(k)) }
 59
 60	var argv []string
 61	switch r.FormValue("field") {
 62	case "description":
 63		argv = []string{"repo", "settings", "description", repo, v("description")}
 64	case "website":
 65		argv = []string{"repo", "settings", "website", repo, v("website")}
 66	case "visibility":
 67		argv = []string{"repo", "settings", "visibility", repo, v("visibility")}
 68	case "git-daemon":
 69		argv = []string{"repo", "settings", "git-daemon", repo, onOff(v("git-daemon"))}
 70	case "require-checks":
 71		argv = []string{"repo", "settings", "require-checks", repo, onOff(v("require-checks"))}
 72	case "require-resolved":
 73		argv = []string{"repo", "settings", "require-resolved", repo, onOff(v("require-resolved"))}
 74	case "require-signed":
 75		argv = []string{"repo", "settings", "require-signed", repo, onOff(v("require-signed"))}
 76	case "require-approvals":
 77		argv = []string{"repo", "settings", "require-approvals", repo, v("approvals")}
 78	case "protect":
 79		argv = []string{"repo", "settings", "protect", repo, v("branch")}
 80	case "unprotect":
 81		argv = []string{"repo", "settings", "unprotect", repo, v("branch")}
 82	case "archive":
 83		verb := "archive"
 84		if v("archive") != "on" {
 85			verb = "unarchive"
 86		}
 87		argv = []string{"repo", verb, repo}
 88	case "topics":
 89		if add := strings.Fields(v("add")); len(add) > 0 {
 90			argv = append([]string{"repo", "topics", "add", repo}, add...)
 91		} else if rm := strings.Fields(v("remove")); len(rm) > 0 {
 92			argv = append([]string{"repo", "topics", "remove", repo}, rm...)
 93		} else {
 94			s.settingsRedirect(w, r, "name at least one topic")
 95			return
 96		}
 97	default:
 98		s.settingsRedirect(w, r, "unknown setting")
 99		return
100	}
101
102	_, msg, ok := s.runControl(u, argv)
103	if ok {
104		msg = ""
105	}
106	s.settingsRedirect(w, r, msg)
107}
108
109// onOff normalises a checkbox to the on|off the commands take.
110func onOff(v string) string {
111	if v == "on" || v == "true" {
112		return "on"
113	}
114	return "off"
115}