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