summaryrefslogtreecommitdiff
path: root/pkg/webui/states_new.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--pkg/webui/states_new.go84
1 files changed, 84 insertions, 0 deletions
diff --git a/pkg/webui/states_new.go b/pkg/webui/states_new.go
new file mode 100644
index 0000000..8551191
--- /dev/null
+++ b/pkg/webui/states_new.go
@@ -0,0 +1,84 @@
+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 StatesNewPage struct {
+ Page *Page
+ fileError bool
+ Path string
+ PathDuplicate bool
+ PathError bool
+}
+
+var statesNewTemplates = template.Must(template.ParseFS(htmlFS, "html/base.html", "html/states_new.html"))
+
+func handleStatesNewGET(db *database.DB) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ render(w, statesNewTemplates, http.StatusOK, StatesNewPage{
+ Page: makePage(r, &Page{Title: "New State", Section: "states"}),
+ })
+ })
+}
+
+func handleStatesNewPOST(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, statesNewTemplates, http.StatusBadRequest, StatesNewPage{
+ 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, statesNewTemplates, http.StatusBadRequest, StatesNewPage{
+ 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)
+ })
+}