diff --git a/README.md b/README.md index 266ef28..55fa180 100644 --- a/README.md +++ b/README.md @@ -322,7 +322,10 @@ This is just enough code to get a simple JSON API going that we can load from th you've been editing. To grab the data just do this: ```javascript - const data = await GetJson('/api/myfeature/user_profile'); + const [data, status] = await $get_json('/api/myfeature/user_profile'); + if($no_error(data, status)) { + // use it + } ``` In place of your prototype data. Doing that will get the data from the `api.go` code you just diff --git a/features/admin/api.go b/features/admin/api.go index 5a749b0..bca9b08 100644 --- a/features/admin/api.go +++ b/features/admin/api.go @@ -3,6 +3,7 @@ package features_admin import ( "maps" "reflect" + "fmt" "github.com/gofiber/fiber/v2" "MY/webapp/data" . "MY/webapp/common" @@ -64,17 +65,27 @@ func GetApiSelectOne(c *fiber.Ctx) error { func PostApiUpdate(c *fiber.Ctx) error { _, err := AuthCheck(c, true) - if err != nil { return c.Redirect("/") } + if err != nil { + return ApiError(c, "Auth required.") + } table := c.Params("table") - typeOf := data.Models()[table] + typeOf, ok := data.Models()[table] + if !ok { + return ApiError(c, "Table does not exist") + } + obj, err := ReflectOnPost(typeOf, c) - if err != nil { return IfErrNil(err, c) } + if err != nil { + return ApiError(c, fmt.Sprintf("Invalid format: %v", err)) + } - err = Update(table, obj.Elem()) - if err != nil { return IfErrNil(err, c) } + id, err := Update(table, obj.Elem()) + if err != nil { + return ApiError(c, "Update failed") + } - return c.RedirectBack("/admin/table/", 303) + return c.JSON(fiber.Map{"table": table, "id": id}) } func GetApiInsert(c *fiber.Ctx) error { diff --git a/features/admin/db.go b/features/admin/db.go index 3fb25b1..2b3e080 100644 --- a/features/admin/db.go +++ b/features/admin/db.go @@ -3,13 +3,16 @@ package features_admin import ( "reflect" "fmt" + "errors" "MY/webapp/data" _ "github.com/mattn/go-sqlite3" sq "github.com/Masterminds/squirrel" ) -func Schema(table string) []string { - the_type := data.Models()[table] +func Schema(table string) ([]string, error) { + the_type, ok := data.Models()[table] + if !ok { return nil, errors.New("Invalid table") } + field_num := the_type.NumField() fields := make([]string, 0, field_num) @@ -19,7 +22,7 @@ func Schema(table string) []string { fields = append(fields, tag) } - return fields + return fields, nil } func SearchTable(search string, table string, limit uint64, page uint64) ([]any, error) { @@ -140,8 +143,9 @@ func Insert(table string, value reflect.Value) (int64, int64, error) { return id, count, err } -func Update(table string, value reflect.Value) error { +func Update(table string, value reflect.Value) (int64, error) { builder := sq.Update(table) + orig_id := value.FieldByName("Id").Int() type_of := value.Type() field_num := value.NumField() @@ -156,13 +160,15 @@ func Update(table string, value reflect.Value) error { builder = builder.Set(tag, field.Interface()) } - builder = builder.Where(sq.Eq{"id": value.FieldByName("Id").Interface()}) + builder = builder.Where(sq.Eq{"id": orig_id}) sql_query, args, err := builder.ToSql() - if err != nil { return err } + if err != nil { return -1, err } fmt.Println("UPDATE QUERY", sql_query, args) - if err != nil { return err} + if err != nil { return -1, err} _, err = data.DB.Exec(sql_query, args...) - return err + if err != nil { return -1, err } + + return orig_id, err } diff --git a/features/admin/views.go b/features/admin/views.go index d83cbe9..1bf9ae6 100644 --- a/features/admin/views.go +++ b/features/admin/views.go @@ -25,7 +25,11 @@ func GetPageContent(c *fiber.Ctx) error { table := c.Params("table") - headers := Schema(table) + headers, err := Schema(table) + + if err != nil { + return ApiError(c, "Invalid table") + } return c.Render("admin/table/contents", fiber.Map{ "table": table, @@ -36,7 +40,7 @@ func GetPageContent(c *fiber.Ctx) error { func SetupPages(app *fiber.App) { AddAuthedPage(app, true, "admin/table/", "admin/table/index") AddAuthedPage(app, true, "admin/table/new/:table/", "admin/table/new") - AddPage(app, "admin/", "admin/index") + AddAuthedPage(app, true, "admin/", "admin/index") app.Get("admin/table/:table/", GetPageContent) app.Get("/admin/table/:table/:id/", GetPageSelectOne) diff --git a/features/auth/api.go b/features/auth/api.go index 9d0dbaf..060ee67 100644 --- a/features/auth/api.go +++ b/features/auth/api.go @@ -4,8 +4,8 @@ import ( "github.com/gofiber/fiber/v2" _ "github.com/mattn/go-sqlite3" sq "github.com/Masterminds/squirrel" + "log" - "fmt" "MY/webapp/data" . "MY/webapp/common" ) @@ -44,13 +44,11 @@ func PostApiLogin(c *fiber.Ctx) error { var user data.User login, err := ReceivePost[data.Login](c) - if(err != nil) { return IfErrNil(err, c) } + if(err != nil) { + return ApiError(c, "Invalid login form.") + } pass_good, err := LoginUser(&user, login) - if err != nil { - fmt.Println("!!!!!!!!!!!!!!! YOU SUCK, make this show a form/login error.") - return c.Redirect("/login/") - } if pass_good { sess, err := STORE.Get(c) @@ -59,12 +57,18 @@ func PostApiLogin(c *fiber.Ctx) error { sess.Set("user_id", user.Id) sess.Set("authenticated", true) sess.Set("admin", IsAdmin(&user)) + err = sess.Save() - if err != nil { return IfErrNil(err, c) } + if err != nil { + return ApiError(c, "Server Failure in Session.") + } - return c.Redirect("/") + return c.JSON(fiber.Map{"valid": true}) } else { - return c.Redirect("/login/") + // custom auth error + if(err != nil) { log.Printf("Error in login: %v", err) } + c.Status(401) + return c.JSON(fiber.Map{"error": "Invalid login."}) } } diff --git a/pages/login/index.html b/pages/login/index.html index 5509c18..f49578d 100644 --- a/pages/login/index.html +++ b/pages/login/index.html @@ -1,5 +1,22 @@ + + +
+ +
-
+

Login

diff --git a/static/js/code.js b/static/js/code.js index 0d9755b..504ce54 100644 --- a/static/js/code.js +++ b/static/js/code.js @@ -67,12 +67,6 @@ class ForeverScroll { } } -const GetJson = async (url) => { - const resp = await fetch(url); - console.assert(resp.status == 200, "failed to get it"); - return await resp.json(); -} - const ConfirmDelete = async (table, obj_id) => { if(confirm("Are you sure?")) { await fetch("/api/admin/table/" + table + "/" + obj_id, diff --git a/static/js/jzed.js b/static/js/jzed.js index c0fe4ec..23965cd 100644 --- a/static/js/jzed.js +++ b/static/js/jzed.js @@ -299,11 +299,21 @@ const $form_submit = async (form_id, event) => { } const $handle_form = (form_id, cb) => { + const form = $id(form_id); + if(!form) { + console.error("There's no form named", form_id); + return; + } + const submitter = async (event) => { const [data, status] = await $form_submit(form_id, event); cb(data, status); } - $id('form').addEventListener('submit', submitter); + form.addEventListener('submit', submitter); } +const $get_json = async (url) => { + const resp = await fetch(url); + return [await resp.json(), resp.status]; +} diff --git a/tests/admin/admin_test.go b/tests/admin/admin_test.go index caff5b0..c60224d 100644 --- a/tests/admin/admin_test.go +++ b/tests/admin/admin_test.go @@ -64,10 +64,11 @@ func TestAdminIndexPage(t *testing.T) { result.FieldByName("Username").SetString("joeblow") result.FieldByName("Email").SetString("what@what.com") - err = admin.Update(table, result) - assert.NoError(err, ) + update_id, err := admin.Update(table, result) + assert.NoError(err) + assert.Equal(id.Int(), update_id) - err = admin.Delete(table, id.Int()) + err = admin.Delete(table, update_id) assert.NoError(err) } } diff --git a/views/admin/table/new.html b/views/admin/table/new.html index a93a7c6..a121554 100644 --- a/views/admin/table/new.html +++ b/views/admin/table/new.html @@ -1,17 +1,12 @@ diff --git a/views/admin/table/view.html b/views/admin/table/view.html index fba5ce0..97614bf 100644 --- a/views/admin/table/view.html +++ b/views/admin/table/view.html @@ -1,20 +1,34 @@

«Admin {{ .table }}

+
+ - +

{{ .table }} : {{ .id }}

diff --git a/views/layouts/main.html b/views/layouts/main.html index 6cef227..a2df154 100644 --- a/views/layouts/main.html +++ b/views/layouts/main.html @@ -13,11 +13,14 @@ Go Web Dev Starter Kit