Files
lpra/internal/server/frag.go
T

89 lines
2.8 KiB
Go

package server
import (
"bytes"
"html/template"
"log"
"net/http"
)
// A panel page is either a fragment - its content alone, for the shell to put
// in place without reloading - or the shell with that content already in it.
func isFrag(r *http.Request) bool { return r.URL.Query().Get("frag") == "1" }
// pageView is the shell's view a page is shown in; the machine pages (Порты,
// Статус, Изменить) open as a dialog over the machines view.
var pageView = map[string]string{"dashboard": "dashboard", "settings": "settings"}
func (s *Server) renderPage(w http.ResponseWriter, r *http.Request, name string, data map[string]any) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Header().Set("Cache-Control", "no-store")
if data == nil {
data = map[string]any{}
}
data["IsAdmin"] = s.currentAdmin(r).IsAdmin()
if !isFrag(r) {
if _, ok := pageView[name]; !ok {
// A machine page asked for whole: the machines view with it in
// a dialog.
s.shell(w, r, map[string]any{"View": "dashboard", "Dialog": r.URL.Path})
return
}
}
var body bytes.Buffer
if err := s.tmpl.ExecuteTemplate(&body, name+"-body", data); err != nil {
log.Printf("template %s: %v", name, err)
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
if isFrag(r) {
_, _ = w.Write(body.Bytes())
return
}
data["View"] = pageView[name]
data["Body"] = template.HTML(body.String())
s.shell(w, r, data)
}
// shell writes the shell page with data (View, Body, Open, Dialog).
func (s *Server) shell(w http.ResponseWriter, r *http.Request, data map[string]any) {
data["IsAdmin"] = s.currentAdmin(r).IsAdmin()
if data["View"] == "dashboard" && data["Body"] == nil {
// The machines list under a dialog: draw it too.
var body bytes.Buffer
if err := s.tmpl.ExecuteTemplate(&body, "dashboard-body", s.dashboardData(r)); err == nil {
data["Body"] = template.HTML(body.String())
}
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Header().Set("Cache-Control", "no-store")
if err := s.tmpl.ExecuteTemplate(w, "app.html", data); err != nil {
log.Printf("template app.html: %v", err)
}
}
// handleShell serves the shell alone: the terminal view, or with a pane of
// a machine opened at once (/agents/{id}/terminal, /agents/{id}/files).
func (s *Server) handleShell(w http.ResponseWriter, r *http.Request) {
data := map[string]any{"View": "terminal"}
if id := r.PathValue("id"); id != "" {
a, _ := s.db.GetAgent(id)
if a == nil {
http.NotFound(w, r)
return
}
kind := "term"
switch r.PathValue("kind") {
case "", "terminal":
case "files":
kind = "files"
default:
http.NotFound(w, r)
return
}
data["Open"] = map[string]any{"kind": kind, "agent": map[string]string{"id": a.ID, "name": a.Name, "host": a.Hostname, "user": a.TerminalUser()}}
}
s.shell(w, r, data)
}