arche / internal/archesrv/handlers_admin.go

commit 154431fd
  1package archesrv
  2
  3import (
  4	"fmt"
  5	"net/http"
  6	"strings"
  7
  8	"arche/internal/repo"
  9)
 10
 11type adminUsersData struct {
 12	User  *User
 13	Users []User
 14}
 15
 16func (s *forgeServer) handleAdminUsers(w http.ResponseWriter, r *http.Request) {
 17	user := s.db.currentUser(r)
 18	if user == nil || !user.IsAdmin {
 19		http.Error(w, "forbidden", http.StatusForbidden)
 20		return
 21	}
 22	users, err := s.db.ListUsers()
 23	if err != nil {
 24		http.Error(w, "list users: "+err.Error(), http.StatusInternalServerError)
 25		return
 26	}
 27	s.render(w, "srv_admin_users.html", adminUsersData{User: user, Users: users})
 28}
 29
 30func (s *forgeServer) handleAdminCreateUser(w http.ResponseWriter, r *http.Request) {
 31	user := s.db.currentUser(r)
 32	if user == nil || !user.IsAdmin {
 33		http.Error(w, "forbidden", http.StatusForbidden)
 34		return
 35	}
 36	r.ParseForm() //nolint:errcheck
 37	username := strings.TrimSpace(r.FormValue("username"))
 38	password := r.FormValue("password")
 39	isAdmin := r.FormValue("is_admin") == "1"
 40	if username == "" || password == "" {
 41		http.Error(w, "username and password required", http.StatusBadRequest)
 42		return
 43	}
 44	if _, err := s.db.CreateUser(username, password, isAdmin); err != nil {
 45		http.Error(w, "create user: "+err.Error(), http.StatusInternalServerError)
 46		return
 47	}
 48	s.log.Info("user created", "by", user.Username, "new_user", username, "is_admin", isAdmin)
 49	http.Redirect(w, r, "/admin/users", http.StatusFound)
 50}
 51
 52func (s *forgeServer) handleAdminDeleteUser(w http.ResponseWriter, r *http.Request) {
 53	user := s.db.currentUser(r)
 54	if user == nil || !user.IsAdmin {
 55		http.Error(w, "forbidden", http.StatusForbidden)
 56		return
 57	}
 58	idStr := r.PathValue("id")
 59	var targetID int64
 60	if _, err := fmt.Sscan(idStr, &targetID); err != nil {
 61		http.Error(w, "invalid user id", http.StatusBadRequest)
 62		return
 63	}
 64	if targetID == user.ID {
 65		http.Error(w, "cannot delete your own account", http.StatusBadRequest)
 66		return
 67	}
 68	if err := s.db.DeleteUser(targetID); err != nil {
 69		http.Error(w, "delete user: "+err.Error(), http.StatusInternalServerError)
 70		return
 71	}
 72	s.log.Info("user deleted", "by", user.Username, "target_id", targetID)
 73	w.WriteHeader(http.StatusNoContent)
 74}
 75
 76func (s *forgeServer) handleAdminCreateRepo(w http.ResponseWriter, r *http.Request) {
 77	user := s.db.currentUser(r)
 78	if user == nil || !user.IsAdmin {
 79		http.Error(w, "forbidden", http.StatusForbidden)
 80		return
 81	}
 82
 83	r.ParseForm() //nolint:errcheck
 84	name := strings.TrimSpace(r.FormValue("name"))
 85	desc := r.FormValue("description")
 86	vis := r.FormValue("visibility")
 87
 88	if name == "" {
 89		http.Error(w, "name required", http.StatusBadRequest)
 90		return
 91	}
 92
 93	rec, err := s.db.CreateRepo(name, desc, vis)
 94	if err != nil {
 95		http.Error(w, "create repo: "+err.Error(), http.StatusInternalServerError)
 96		return
 97	}
 98
 99	path := repoPath(s.dataDir(), name)
100	if _, err := repo.Init(path); err != nil {
101		s.db.DeleteRepo(name) //nolint:errcheck
102		http.Error(w, "init repo: "+err.Error(), http.StatusInternalServerError)
103		return
104	}
105
106	s.db.SetPermission(rec.ID, user.ID, "admin") //nolint:errcheck
107	s.log.Info("repo created", "by", user.Username, "repo", rec.Name, "visibility", vis)
108	fmt.Fprintf(w, `{"name":%q}`, rec.Name)
109}
110
111func (s *forgeServer) handleAdminDeleteRepo(w http.ResponseWriter, r *http.Request) {
112	user := s.db.currentUser(r)
113	if user == nil || !user.IsAdmin {
114		http.Error(w, "forbidden", http.StatusForbidden)
115		return
116	}
117	name := r.PathValue("name")
118	if err := s.db.DeleteRepo(name); err != nil {
119		http.Error(w, "delete repo: "+err.Error(), http.StatusInternalServerError)
120		return
121	}
122	s.log.Info("repo deleted", "by", user.Username, "repo", name)
123	w.WriteHeader(http.StatusNoContent)
124}
125
126type srvAdminInvitesData struct {
127	User    *User
128	Invites []InviteToken
129	Link    string
130}
131
132func (s *forgeServer) handleAdminInvites(w http.ResponseWriter, r *http.Request) {
133	user := s.db.currentUser(r)
134	if user == nil || !user.IsAdmin {
135		http.Error(w, "forbidden", http.StatusForbidden)
136		return
137	}
138	invites, err := s.db.ListInvites(user.ID)
139	if err != nil {
140		http.Error(w, "list invites: "+err.Error(), http.StatusInternalServerError)
141		return
142	}
143	s.render(w, "srv_admin_invites.html", srvAdminInvitesData{User: user, Invites: invites})
144}
145
146func (s *forgeServer) handleAdminCreateInvite(w http.ResponseWriter, r *http.Request) {
147	user := s.db.currentUser(r)
148	if user == nil || !user.IsAdmin {
149		http.Error(w, "forbidden", http.StatusForbidden)
150		return
151	}
152	inv, err := s.db.CreateInvite(user.ID)
153	if err != nil {
154		http.Error(w, "create invite: "+err.Error(), http.StatusInternalServerError)
155		return
156	}
157	invites, _ := s.db.ListInvites(user.ID)
158	s.render(w, "srv_admin_invites.html", srvAdminInvitesData{
159		User:    user,
160		Invites: invites,
161		Link:    "/register?invite=" + inv.Token,
162	})
163}
164
165func (s *forgeServer) handleAdminDeleteInvite(w http.ResponseWriter, r *http.Request) {
166	user := s.db.currentUser(r)
167	if user == nil || !user.IsAdmin {
168		http.Error(w, "forbidden", http.StatusForbidden)
169		return
170	}
171	var id int64
172	if _, err := fmt.Sscan(r.PathValue("id"), &id); err != nil {
173		http.Error(w, "invalid id", http.StatusBadRequest)
174		return
175	}
176	if err := s.db.DeleteInvite(id, user.ID); err != nil {
177		http.Error(w, "delete invite: "+err.Error(), http.StatusInternalServerError)
178		return
179	}
180	w.WriteHeader(http.StatusNoContent)
181}