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 }