diff options
author | Julien Dessaux | 2025-02-22 00:35:17 +0100 |
---|---|---|
committer | Julien Dessaux | 2025-02-22 00:35:17 +0100 |
commit | 169e2d0d9d253c316fa322d3200230704b57fb76 (patch) | |
tree | ca57a7cd26de1f332bc5dbc516a31474847ad5ad /pkg/webui/states.go | |
parent | chore(deps): update dependencies (diff) | |
download | tfstated-169e2d0d9d253c316fa322d3200230704b57fb76.tar.gz tfstated-169e2d0d9d253c316fa322d3200230704b57fb76.tar.bz2 tfstated-169e2d0d9d253c316fa322d3200230704b57fb76.zip |
chore(webui): refactored state creation page and route
Diffstat (limited to 'pkg/webui/states.go')
-rw-r--r-- | pkg/webui/states.go | 74 |
1 files changed, 69 insertions, 5 deletions
diff --git a/pkg/webui/states.go b/pkg/webui/states.go index a0d16ca..85303fe 100644 --- a/pkg/webui/states.go +++ b/pkg/webui/states.go @@ -1,29 +1,93 @@ package webui import ( + "fmt" "html/template" + "io" "net/http" + "net/url" + "path" + "strconv" "git.adyxax.org/adyxax/tfstated/pkg/database" "git.adyxax.org/adyxax/tfstated/pkg/model" ) +type StatesPage struct { + ActiveTab int + Page *Page + Path string + PathError bool + PathDuplicate bool + States []model.State +} + var statesTemplates = template.Must(template.ParseFS(htmlFS, "html/base.html", "html/states.html")) func handleStatesGET(db *database.DB) http.Handler { - type StatesData struct { - Page *Page - States []model.State - } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { states, err := db.LoadStates() if err != nil { errorResponse(w, http.StatusInternalServerError, err) return } - render(w, statesTemplates, http.StatusOK, StatesData{ + render(w, statesTemplates, http.StatusOK, StatesPage{ Page: makePage(r, &Page{Title: "States", Section: "states"}), States: states, }) }) } + +func handleStatesPOST(db *database.DB) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // file upload limit of 20MB + if err := r.ParseMultipartForm(20 << 20); err != nil { + errorResponse(w, http.StatusBadRequest, err) + return + } + file, _, err := r.FormFile("file") + if err != nil { + errorResponse(w, http.StatusBadRequest, err) + return + } + defer file.Close() + statePath := r.FormValue("path") + parsedStatePath, err := url.Parse(statePath) + if err != nil || path.Clean(parsedStatePath.Path) != statePath || statePath[0] != '/' { + render(w, statesTemplates, http.StatusBadRequest, StatesPage{ + ActiveTab: 1, + Page: makePage(r, &Page{Title: "New State", Section: "states"}), + Path: statePath, + PathError: true, + }) + return + } + data, err := io.ReadAll(file) + if err != nil { + errorResponse(w, http.StatusBadRequest, fmt.Errorf("failed to read uploaded file: %w", err)) + return + } + fileType := http.DetectContentType(data) + if fileType != "text/plain; charset=utf-8" { + errorResponse(w, http.StatusBadRequest, fmt.Errorf("invalid file type: expected \"text/plain; charset=utf-8\" but got \"%s\"", fileType)) + return + } + account := r.Context().Value(model.AccountContextKey{}).(*model.Account) + version, err := db.CreateState(statePath, account.Id, data) + if err != nil { + errorResponse(w, http.StatusInternalServerError, err) + return + } + if version == nil { + render(w, statesTemplates, http.StatusBadRequest, StatesPage{ + ActiveTab: 1, + Page: makePage(r, &Page{Title: "New State", Section: "states"}), + Path: statePath, + PathDuplicate: true, + }) + return + } + destination := path.Join("/version", strconv.Itoa(version.Id)) + http.Redirect(w, r, destination, http.StatusFound) + }) +} |