summaryrefslogtreecommitdiff
path: root/pkg/webui/states.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--pkg/webui/states.go73
1 files changed, 68 insertions, 5 deletions
diff --git a/pkg/webui/states.go b/pkg/webui/states.go
index a0d16ca..c68b2c9 100644
--- a/pkg/webui/states.go
+++ b/pkg/webui/states.go
@@ -1,29 +1,92 @@
package webui
import (
+ "fmt"
"html/template"
+ "io"
"net/http"
+ "net/url"
+ "path"
"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", version.Id.String())
+ http.Redirect(w, r, destination, http.StatusFound)
+ })
+}