internal/httpd/settings.go
124 lines · 3688 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 DepsEnabled bool
23 Notice string
24}
25
26func (s *Server) settingsForm(w http.ResponseWriter, r *http.Request, u store.User) {
27 repo, ok := s.repoForUser(w, r, u, policyCanAdmin)
28 if !ok {
29 return
30 }
31 p, ok := s.repoFor(w, r, "")
32 if !ok {
33 return
34 }
35 p.Tab = "settings"
36 topics, _ := s.st.ListTopics(repo.ID)
37 branches, _ := gitutil.Refs(p.Dir, "heads")
38 _, depsErr := s.st.DepCheckFor(repo.ID)
39 s.render(w, "settings.html", settingsPage{
40 repoPage: p, Topics: topics, Branches: branches,
41 DepsEnabled: depsErr == nil,
42 Notice: r.URL.Query().Get("e"),
43 })
44}
45
46func (s *Server) settingsRedirect(w http.ResponseWriter, r *http.Request, msg string) {
47 dest := fmt.Sprintf("/%s/%s/settings", r.PathValue("owner"), r.PathValue("repo"))
48 if msg != "" {
49 if len(msg) > 300 {
50 msg = msg[:300]
51 }
52 dest += "?e=" + url.QueryEscape(msg)
53 }
54 http.Redirect(w, r, dest, http.StatusSeeOther)
55}
56
57// settingsSubmit routes one form to its command. Keeping the mapping in
58// one place makes what the page can reach obvious.
59func (s *Server) settingsSubmit(w http.ResponseWriter, r *http.Request, u store.User) {
60 repo := r.PathValue("owner") + "/" + r.PathValue("repo")
61 v := func(k string) string { return strings.TrimSpace(r.FormValue(k)) }
62
63 var argv []string
64 switch r.FormValue("field") {
65 case "description":
66 argv = []string{"repo", "settings", "description", repo, v("description")}
67 case "website":
68 argv = []string{"repo", "settings", "website", repo, v("website")}
69 case "visibility":
70 argv = []string{"repo", "settings", "visibility", repo, v("visibility")}
71 case "git-daemon":
72 argv = []string{"repo", "settings", "git-daemon", repo, onOff(v("git-daemon"))}
73 case "require-checks":
74 argv = []string{"repo", "settings", "require-checks", repo, onOff(v("require-checks"))}
75 case "require-resolved":
76 argv = []string{"repo", "settings", "require-resolved", repo, onOff(v("require-resolved"))}
77 case "require-signed":
78 argv = []string{"repo", "settings", "require-signed", repo, onOff(v("require-signed"))}
79 case "require-approvals":
80 argv = []string{"repo", "settings", "require-approvals", repo, v("approvals")}
81 case "protect":
82 argv = []string{"repo", "settings", "protect", repo, v("branch")}
83 case "unprotect":
84 argv = []string{"repo", "settings", "unprotect", repo, v("branch")}
85 case "deps":
86 verb := "disable"
87 if v("deps") == "on" {
88 verb = "enable"
89 }
90 argv = []string{"repo", "deps", verb, repo}
91 case "archive":
92 verb := "archive"
93 if v("archive") != "on" {
94 verb = "unarchive"
95 }
96 argv = []string{"repo", verb, repo}
97 case "topics":
98 if add := strings.Fields(v("add")); len(add) > 0 {
99 argv = append([]string{"repo", "topics", "add", repo}, add...)
100 } else if rm := strings.Fields(v("remove")); len(rm) > 0 {
101 argv = append([]string{"repo", "topics", "remove", repo}, rm...)
102 } else {
103 s.settingsRedirect(w, r, "name at least one topic")
104 return
105 }
106 default:
107 s.settingsRedirect(w, r, "unknown setting")
108 return
109 }
110
111 _, msg, ok := s.runControl(u, argv)
112 if ok {
113 msg = ""
114 }
115 s.settingsRedirect(w, r, msg)
116}
117
118// onOff normalises a checkbox to the on|off the commands take.
119func onOff(v string) string {
120 if v == "on" || v == "true" {
121 return "on"
122 }
123 return "off"
124}