From e29f38937cdf077a99b45c27e49f553d4dd8d0d7 Mon Sep 17 00:00:00 2001 From: Gibheer Date: Thu, 15 Dec 2022 11:16:56 +0100 Subject: [PATCH] monfront - add basic interface to create some entities --- cmd/monfront/create.go | 148 ++++++++++++++++++++++ cmd/monfront/main.go | 1 + cmd/monfront/server.go | 2 + cmd/monfront/templates/create_index.html | 84 ++++++++++++ cmd/monfront/templates/header.html | 1 + cmd/monfront/templates/rows_to_table.html | 19 +++ 6 files changed, 255 insertions(+) create mode 100644 cmd/monfront/create.go create mode 100644 cmd/monfront/templates/create_index.html create mode 100644 cmd/monfront/templates/rows_to_table.html diff --git a/cmd/monfront/create.go b/cmd/monfront/create.go new file mode 100644 index 0000000..43805a1 --- /dev/null +++ b/cmd/monfront/create.go @@ -0,0 +1,148 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + "net/http" + "strings" +) + +func showCreate(con *Context) { + if con.r.Method == "POST" { + addCreate(con) + return + } + if con.r.Method != "GET" { + con.w.WriteHeader(http.StatusMethodNotAllowed) + con.w.Write([]byte("method is not supported")) + return + } + if !con.CanEdit { + con.w.WriteHeader(http.StatusForbidden) + con.w.Write([]byte("no permission to change data")) + return + } + con.Content = map[string]any{} + + primitives := []struct { + name string + query string + }{ + {"commands", "select id, name, updated, command, message from commands order by name"}, + {"checkers", "select id, name, description from checkers order by name"}, + {"notifier", "select id, name, settings from notifier order by name"}, + {"nodes", "select id, name, updated, message from nodes order by name"}, + } + for _, prim := range primitives { + rows, err := DB.Query(prim.query) + defer rows.Close() + if err != nil { + log.Printf("could not get commands: %s", err) + con.Error = "could not get commands" + returnError(http.StatusInternalServerError, con, con.w) + return + } + result, err := rowsToResult(rows) + if err != nil { + log.Printf("could not get %s: %s", prim.name, err) + con.Error = "could not get " + prim.name + returnError(http.StatusInternalServerError, con, con.w) + return + } + con.Content[prim.name] = result + } + + con.w.Header()["Content-Type"] = []string{"text/html"} + con.Render("create_index") + return +} + +type ( + sqlResult struct { + Columns []string + Rows [][]sql.NullString + } +) + +func rowsToResult(rows *sql.Rows) (*sqlResult, error) { + res := &sqlResult{} + cols, err := rows.Columns() + if err != nil { + return res, fmt.Errorf("could not get columns: %w", err) + } + res.Columns = cols + res.Rows = [][]sql.NullString{} + colNum := len(cols) + + for rows.Next() { + line := make([]sql.NullString, colNum) + lineMap := make([]any, colNum) + for i := 0; i < colNum; i++ { + lineMap[i] = &(line[i]) + } + if err := rows.Scan(lineMap...); err != nil { + return res, fmt.Errorf("could not scan values: %w", err) + } + res.Rows = append(res.Rows, line) + } + + return res, nil +} + +func addCreate(con *Context) { + if !con.CanEdit { + con.w.WriteHeader(http.StatusForbidden) + con.w.Write([]byte("no permission to change data")) + return + } + + if err := con.r.ParseForm(); err != nil { + con.w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(con.w, "could not parse parameters: %s", err) + return + } + + con.w.Header()["Location"] = []string{"/create"} + + addType := con.r.PostForm.Get("type") + types := map[string]struct { + Fields []string + Table string + }{ + "command": {[]string{"name", "command", "message"}, "commands"}, + "node": {[]string{"name", "message"}, "nodes"}, + "checker": {[]string{"name", "description"}, "checkers"}, + "notifier": {[]string{"name", "settings"}, "notifier"}, + "check": {[]string{"name", "message", "options", "intval", "node_id", "command_id", "checker_id"}, "checks"}, + } + t, found := types[addType] + if !found { + con.Error = "undefined type '" + addType + "'" + returnError(http.StatusBadRequest, con, con.w) + return + } + + fields := make([]any, len(t.Fields)) + vals := make([]string, len(t.Fields)) + for i := 0; i < len(fields); i++ { + vals[i] = fmt.Sprintf(`$%d`, i+1) + fields[i] = con.r.PostForm.Get(t.Fields[i]) + if fields[i] == "" { + con.Error = "field " + t.Fields[i] + " must not be empty" + returnError(http.StatusBadRequest, con, con.w) + return + } + } + stmt := `insert into ` + t.Table + `(` + strings.Join(t.Fields, ",") + `) values (` + strings.Join(vals, ",") + `)` + _, err := DB.Exec(stmt, fields...) + if err != nil { + log.Printf("could not insert new %s: %s", addType, err) + con.Error = "could not insert new " + addType + returnError(http.StatusInternalServerError, con, con.w) + return + } + + con.w.WriteHeader(http.StatusSeeOther) + return +} diff --git a/cmd/monfront/main.go b/cmd/monfront/main.go index 63c1b9a..a318e75 100644 --- a/cmd/monfront/main.go +++ b/cmd/monfront/main.go @@ -170,6 +170,7 @@ func main() { s := newServer(l, db, tmpl, auth, autho) s.Handle("/", showChecks) + s.Handle("/create", showCreate) s.Handle("/check", showCheck) s.Handle("/checks", showChecks) s.Handle("/groups", showGroups) diff --git a/cmd/monfront/server.go b/cmd/monfront/server.go index 2ada1d0..8e53c64 100644 --- a/cmd/monfront/server.go +++ b/cmd/monfront/server.go @@ -46,6 +46,8 @@ type ( CheckDetails *checkDetails `json:"check_details,omitempty"` Groups []group `json:"groups,omitempty"` Unhandled bool `json:"-"` // set this flag when unhandled was called + + Content map[string]any `json:"-"` // used for the configuration dashboard } ) diff --git a/cmd/monfront/templates/create_index.html b/cmd/monfront/templates/create_index.html new file mode 100644 index 0000000..1e4a67e --- /dev/null +++ b/cmd/monfront/templates/create_index.html @@ -0,0 +1,84 @@ +{{ template "header" . }} +
+

create entries

+
+ checks +
+

+

+ +

+

+

+

+
+ options + +
+

+

+
+
+
+ nodes +
+ create new node +
+

+

+

+
+
+ {{ template "rows_to_table" .Content.nodes }} +
+
+ commands +
+ create new command +
+

+

+

+

+
+
+ {{ template "rows_to_table" .Content.commands }} +
+
+ checkers +
+ create new checker instance +
+

+

+

+
+
+ {{ template "rows_to_table" .Content.checkers }} +
+
+ notifier +
+ create new notifier +
+

+

+

+
+
+ {{ template "rows_to_table" .Content.notifier }} +
+
+{{ template "footer" . }} diff --git a/cmd/monfront/templates/header.html b/cmd/monfront/templates/header.html index c31a43c..aa8fe4b 100644 --- a/cmd/monfront/templates/header.html +++ b/cmd/monfront/templates/header.html @@ -92,6 +92,7 @@
  • home
  • checks
  • groups
  • +
  • create
  • {{ if .Error }}
    {{ .Error }}
    {{ end }} diff --git a/cmd/monfront/templates/rows_to_table.html b/cmd/monfront/templates/rows_to_table.html new file mode 100644 index 0000000..04add21 --- /dev/null +++ b/cmd/monfront/templates/rows_to_table.html @@ -0,0 +1,19 @@ + + + {{ range $col := .Columns }} + + {{ end }} + + + {{ range $row := .Rows }} + + {{ range $col := $row }} + + {{ end }} + + + {{ end }} +
    {{ $col }}
    {{ if $col.Valid }}{{ $col.String }}{{ end }} + + +