diff options
author | Julien Dessaux | 2025-01-22 00:46:49 +0100 |
---|---|---|
committer | Julien Dessaux | 2025-01-22 00:46:49 +0100 |
commit | 09885ef1e4b7610d05377596f02d08c5079c0434 (patch) | |
tree | 9c8322ea718f1eb721a4c685cb95386fa84bb797 | |
parent | chore(webui): refactor login and session middleware handling (diff) | |
download | tfstated-main.tar.gz tfstated-main.tar.bz2 tfstated-main.zip |
-rw-r--r-- | pkg/database/db.go | 4 | ||||
-rw-r--r-- | pkg/database/states.go | 30 | ||||
-rw-r--r-- | pkg/model/state.go | 13 | ||||
-rw-r--r-- | pkg/webui/html/base.html | 12 | ||||
-rw-r--r-- | pkg/webui/html/index.html | 3 | ||||
-rw-r--r-- | pkg/webui/html/states.html | 23 | ||||
-rw-r--r-- | pkg/webui/index.go | 12 | ||||
-rw-r--r-- | pkg/webui/login.go | 2 | ||||
-rw-r--r-- | pkg/webui/routes.go | 1 | ||||
-rw-r--r-- | pkg/webui/states.go | 29 |
10 files changed, 117 insertions, 12 deletions
diff --git a/pkg/database/db.go b/pkg/database/db.go index 9aeec43..eac31eb 100644 --- a/pkg/database/db.go +++ b/pkg/database/db.go @@ -111,6 +111,10 @@ func (db *DB) Exec(query string, args ...any) (sql.Result, error) { return db.writeDB.ExecContext(db.ctx, query, args...) } +func (db *DB) Query(query string, args ...any) (*sql.Rows, error) { + return db.readDB.QueryContext(db.ctx, query, args...) +} + func (db *DB) QueryRow(query string, args ...any) *sql.Row { return db.readDB.QueryRowContext(db.ctx, query, args...) } diff --git a/pkg/database/states.go b/pkg/database/states.go index d88e717..1bd3d76 100644 --- a/pkg/database/states.go +++ b/pkg/database/states.go @@ -6,6 +6,8 @@ import ( "fmt" "slices" "time" + + "git.adyxax.org/adyxax/tfstated/pkg/model" ) // returns true in case of successful deletion @@ -43,6 +45,34 @@ func (db *DB) GetState(path string) ([]byte, error) { return db.dataEncryptionKey.DecryptAES256(encryptedData) } +func (db *DB) LoadStatesByPath() ([]model.State, error) { + rows, err := db.Query( + `SELECT created, id, lock, path, updated FROM states;`) + if err != nil { + return nil, fmt.Errorf("failed to load states from database: %w", err) + } + defer rows.Close() + states := make([]model.State, 0) + for rows.Next() { + var state model.State + var ( + created int64 + updated int64 + ) + err = rows.Scan(&created, &state.Id, &state.Lock, &state.Path, &updated) + if err != nil { + return nil, fmt.Errorf("failed to load states from row: %w", err) + } + state.Created = time.Unix(created, 0) + state.Updated = time.Unix(updated, 0) + states = append(states, state) + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("failed to load states from rows: %w", err) + } + return states, nil +} + // returns true in case of id mismatch func (db *DB) SetState(path string, accountID int, data []byte, lockID string) (bool, error) { encryptedData, err := db.dataEncryptionKey.EncryptAES256(data) diff --git a/pkg/model/state.go b/pkg/model/state.go new file mode 100644 index 0000000..8e1c277 --- /dev/null +++ b/pkg/model/state.go @@ -0,0 +1,13 @@ +package model + +import ( + "time" +) + +type State struct { + Created time.Time + Id int + Lock *string + Path string + Updated time.Time +} diff --git a/pkg/webui/html/base.html b/pkg/webui/html/base.html index 1c15cc5..7821d28 100644 --- a/pkg/webui/html/base.html +++ b/pkg/webui/html/base.html @@ -9,12 +9,20 @@ <title>tfstated</title> </head> <body> - <header> + <header class="container"> + <nav> + <ul> + <li><a href="/"><strong>TFSTATED</strong></a></li> + </ul> + <ul> + <li><a href="/states">States</a></li> + </ul> + </nav> </header> <main class="container"> {{ template "main" . }} </main> - <footer> + <footer class="container"> </footer> </body> </html> diff --git a/pkg/webui/html/index.html b/pkg/webui/html/index.html deleted file mode 100644 index 5c50159..0000000 --- a/pkg/webui/html/index.html +++ /dev/null @@ -1,3 +0,0 @@ -{{ define "main" }} -<h1>TODO</h1> -{{ end }} diff --git a/pkg/webui/html/states.html b/pkg/webui/html/states.html new file mode 100644 index 0000000..8d3d803 --- /dev/null +++ b/pkg/webui/html/states.html @@ -0,0 +1,23 @@ +{{ define "main" }} +<h1>States</h1> +<table class="striped"> + <thead> + <tr> + <th scope="col">Path</th> + <th scope="col">Created</th> + <th scope="col">Updated</th> + <th scope="col">Locked</th> + </tr> + </thead> + <tbody> + {{ range .States }} + <tr> + <th scope="row">{{ .Path }}</th> + <td>{{ .Created }}</td> + <td>{{ .Updated }}</td> + <td>{{ .Lock }}</td> + </tr> + {{ end }} + </tbody> +</table> +{{ end }} diff --git a/pkg/webui/index.go b/pkg/webui/index.go index 9c81729..3a52fc1 100644 --- a/pkg/webui/index.go +++ b/pkg/webui/index.go @@ -1,16 +1,16 @@ package webui import ( - "html/template" + "fmt" "net/http" ) -var indexTemplates = template.Must(template.ParseFS(htmlFS, "html/base.html", "html/index.html")) - func handleIndexGET() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Cache-Control", "no-store, no-cache") - - render(w, indexTemplates, http.StatusOK, nil) + if r.URL.Path == "/" { + http.Redirect(w, r, "/states", http.StatusFound) + } else { + errorResponse(w, http.StatusNotFound, fmt.Errorf("Page not found")) + } }) } diff --git a/pkg/webui/login.go b/pkg/webui/login.go index fda227a..8444e2c 100644 --- a/pkg/webui/login.go +++ b/pkg/webui/login.go @@ -24,7 +24,7 @@ func handleLoginGET() http.Handler { session := r.Context().Value(model.SessionContextKey{}) if session != nil { - http.Redirect(w, r, "/", http.StatusFound) + http.Redirect(w, r, "/states", http.StatusFound) return } diff --git a/pkg/webui/routes.go b/pkg/webui/routes.go index e9a0346..9bf04ec 100644 --- a/pkg/webui/routes.go +++ b/pkg/webui/routes.go @@ -16,6 +16,7 @@ func addRoutes( mux.Handle("GET /login", requireSession(handleLoginGET())) mux.Handle("POST /login", requireSession(handleLoginPOST(db))) mux.Handle("GET /logout", requireLogin(handleLogoutGET(db))) + mux.Handle("GET /states", requireLogin(handleStatesGET(db))) mux.Handle("GET /static/", cache(http.FileServer(http.FS(staticFS)))) mux.Handle("GET /", requireLogin(handleIndexGET())) } diff --git a/pkg/webui/states.go b/pkg/webui/states.go new file mode 100644 index 0000000..3633cb8 --- /dev/null +++ b/pkg/webui/states.go @@ -0,0 +1,29 @@ +package webui + +import ( + "html/template" + "net/http" + + "git.adyxax.org/adyxax/tfstated/pkg/database" + "git.adyxax.org/adyxax/tfstated/pkg/model" +) + +var statesTemplates = template.Must(template.ParseFS(htmlFS, "html/base.html", "html/states.html")) + +func handleStatesGET(db *database.DB) http.Handler { + type StatesData struct { + States []model.State + } + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "no-store, no-cache") + + states, err := db.LoadStatesByPath() + if err != nil { + errorResponse(w, http.StatusInternalServerError, err) + return + } + render(w, statesTemplates, http.StatusOK, StatesData{ + States: states, + }) + }) +} |