diff options
author | Gibheer <gibheer+git@zero-knowledge.org> | 2022-12-15 11:16:56 +0100 |
---|---|---|
committer | Gibheer <gibheer+git@zero-knowledge.org> | 2022-12-15 11:16:56 +0100 |
commit | e29f38937cdf077a99b45c27e49f553d4dd8d0d7 (patch) | |
tree | 38509003a153a0100cb1a69a5d7a752ad2ff7616 | |
parent | 49dac92034f352698429ee1d78d4bfb070006693 (diff) |
monfront - add basic interface to create some entities
-rw-r--r-- | cmd/monfront/create.go | 148 | ||||
-rw-r--r-- | cmd/monfront/main.go | 1 | ||||
-rw-r--r-- | cmd/monfront/server.go | 2 | ||||
-rw-r--r-- | cmd/monfront/templates/create_index.html | 84 | ||||
-rw-r--r-- | cmd/monfront/templates/header.html | 1 | ||||
-rw-r--r-- | cmd/monfront/templates/rows_to_table.html | 19 |
6 files changed, 255 insertions, 0 deletions
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" . }} +<section id="content"> + <h1>create entries</h1> + <details> + <summary>checks</summary> + <form action="/create" method="POST"> + <p><label>name</label><input name="name" /></p> + <p><label>node</label> + <select name="node_id"> + {{ range $node := .Content.nodes.Rows }} + <option value="{{ (index . 0).String }}">{{ (index . 1).String }}</option> + {{ end }} + </select> + </p> + <p><label>command</label><select name="command_id"> + {{ range $node := .Content.commands.Rows }} + <option value="{{ (index . 0).String }}">{{ (index . 1).String }}</option> + {{ end }} + </select></p> + <p><label>checker</label><select name="checker_id"> + {{ range $node := .Content.checkers.Rows }} + <option value="{{ (index . 0).String }}">{{ (index . 1).String }}</option> + {{ end }} + </select></p> + <p><label>interval</label><input type="integer" name="interval" value="300" /></p> + <fieldset> + <legend>options</legend> + <!-- TODO implement setting options --> + </fieldset> + <p><label>message</label><textarea name="message"></textarea></p> + <p><button type="submit" name="type" value="check">create</button></p> + </form> + </details> + <details> + <summary>nodes</summary> + <details> + <summary>create new node</summary> + <form action="/create" method="POST"> + <p><label>name</label><input name="name" /></p> + <p><label>message</label><textarea name="message"></textarea></p> + <p><button type="submit" name="type" value="node">create</button></p> + </form> + </details> + {{ template "rows_to_table" .Content.nodes }} + </details> + <details> + <summary>commands</summary> + <details> + <summary>create new command</summary> + <form action="/create" method="POST"> + <p><label>name</label><input name="name" /></p> + <p><label>command</label><textarea name="command"></textarea></p> + <p><label>message</label><textarea name="message"></textarea></p> + <p><button type="submit" name="type" value="command">create</button></p> + </form> + </details> + {{ template "rows_to_table" .Content.commands }} + </details> + <details> + <summary>checkers</summary> + <details> + <summary>create new checker instance</summary> + <form action="/create" method="POST"> + <p><label>name</label><input name="name" /></p> + <p><label>description</label><textarea name="description"></textarea></p> + <p><button type="submit" name="type" value="checker">create</button></p> + </form> + </details> + {{ template "rows_to_table" .Content.checkers }} + </details> + <details> + <summary>notifier</summary> + <details> + <summary>create new notifier</summary> + <form action="/create" method="POST"> + <p><label>name</label><input name="name" /></p> + <p><label>settings</label><textarea name="settings">{}</textarea></p> + <p><button type="submit" name="type" value="notifier">create</button></p> + </form> + </details> + {{ template "rows_to_table" .Content.notifier }} + </details> +</section> +{{ 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 @@ <li><a href="/">home</a></li> <li><a href="/checks?filter-state=1&filter-ack=false">checks</a></li> <li><a href="/groups">groups</a></li> + <li><a href="/create">create</a></li> </ul> </nav> {{ if .Error }}<div class="error">{{ .Error }}</div>{{ 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 @@ + <table> + <tr> + {{ range $col := .Columns }} + <th>{{ $col }}</th> + {{ end }} + <th></th> + </tr> + {{ range $row := .Rows }} + <tr> + {{ range $col := $row }} + <td>{{ if $col.Valid }}{{ $col.String }}{{ end }}</td> + {{ end }} + <td> + <button name="update" value="{{ (index $row 0).String }}">update</button> + <button name="delete" value="{{ (index $row 0).String }}">delete</button> + </td> + </tr> + {{ end }} + </table> |