internal/httpd/settings.go
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}