monfront - add basic interface to create some entities
This commit is contained in:
parent
49dac92034
commit
e29f38937c
148
cmd/monfront/create.go
Normal file
148
cmd/monfront/create.go
Normal file
@ -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
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
)
|
||||
|
||||
|
84
cmd/monfront/templates/create_index.html
Normal file
84
cmd/monfront/templates/create_index.html
Normal file
@ -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" . }}
|
@ -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 }}
|
||||
|
19
cmd/monfront/templates/rows_to_table.html
Normal file
19
cmd/monfront/templates/rows_to_table.html
Normal file
@ -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>
|
Loading…
Reference in New Issue
Block a user