package main import ( "bytes" "fmt" "net/http" "strconv" "brainminder.speedtech.it/internal/request" "brainminder.speedtech.it/internal/response" "brainminder.speedtech.it/internal/validator" "brainminder.speedtech.it/models" "github.com/alexedwards/flow" ) type notebookForm struct { Id int64 `form:"Id"` Title string `form:"Title"` Icon string `form:"Icon"` Description string `form:"Description"` Fields []models.Field Widgets []models.Widget Validator validator.Validator `form:"-"` } func (form *notebookForm) Validate(w http.ResponseWriter, r *http.Request, app *application, data map[string]any) bool { var fullBuf = new(bytes.Buffer) form.Validator.CheckField(form.Title != "", "Title", "Title is required") form.Validator.CheckField(form.Description != "", "Description", "Description is required") if form.Validator.HasErrors() { w.Header().Add("HX-Retarget", "#message") data["messageType"] = "failure" data["messageContent"] = "Impossible to save the notebook" data["messageFieldErrors"] = form.Validator.FieldErrors buf, err := response.Fragment([]string{"partials/message.tmpl"}, "message", data) if err != nil { app.serverError(w, r, err) } fullBuf.Write(buf.Bytes()) if err != nil { app.serverError(w, r, err) } fullBuf.WriteTo(w) w.WriteHeader(http.StatusUnprocessableEntity) return false } return true } func (app *application) notebooks(w http.ResponseWriter, r *http.Request) { data := app.newTemplateData(r) notebookModel := &models.NotebookModel{DB: app.db} var fullBuf = new(bytes.Buffer) rows, _, _ := notebookModel.All() data["notebooks"] = &rows if r.Header.Get("HX-Request") == "true" { err := response.HXFragment(fullBuf, []string{"notebooks/list.tmpl"}, "notebooks:list", data) if err != nil { app.serverError(w, r, err) } fullBuf.WriteString("
") err = response.HXFragmentOOB(fullBuf, []string{"notebooks/list_title.tmpl"}, "page:title", data, "page-title") if err != nil { app.serverError(w, r, err) } fullBuf.WriteTo(w) } else { err := response.Page(w, http.StatusOK, data, []string{"notebooks/index.tmpl", "notebooks/list.tmpl", "notebooks/list_title.tmpl"}) if err != nil { app.serverError(w, r, err) } } w.WriteHeader(http.StatusOK) } func (app *application) notebookCreate(w http.ResponseWriter, r *http.Request) { notebookModel := &models.NotebookModel{DB: app.db} var fullBuf = new(bytes.Buffer) var notebook_id int64 data := app.newTemplateData(r) data["formAction"] = "/notebook/create" data["formTarget"] = "#page-content" switch r.Method { case http.MethodGet: data["notebook"] = notebookForm{ Title: "", Icon: "", Description: "", } if r.Header.Get("HX-Request") == "true" { err := response.HXFragment(fullBuf, []string{"notebooks/form.tmpl"}, "page:content", data) if err != nil { app.serverError(w, r, err) } fullBuf.WriteString("
") err = response.HXFragmentOOB(fullBuf, []string{"notebooks/create_title.tmpl"}, "page:title", data, "page-title") if err != nil { app.serverError(w, r, err) } fullBuf.WriteTo(w) } else { err := response.Page(w, http.StatusOK, data, []string{"notebooks/create_title.tmpl", "notebooks/form.tmpl"}) if err != nil { app.serverError(w, r, err) } } case http.MethodPost: var notebookFromForm notebookForm err := request.DecodePostForm(r, ¬ebookFromForm) if err != nil { app.serverError(w, r, err) } if !notebookFromForm.Validate(w, r, app, data) { return } notebook := &models.Notebook{ Title: notebookFromForm.Title, Icon: notebookFromForm.Icon, Description: notebookFromForm.Description, } notebook_id, err = notebookModel.Create(notebook) if err != nil { app.badRequest(w, err) return } data["formAction"] = fmt.Sprint("/notebook/update/", notebook_id) data["formTarget"] = "#message" data["notebook"] = notebookForm{ Id: notebook_id, Title: notebook.Title, Icon: notebook.Icon, Description: notebook.Description, } err = response.HXFragment(fullBuf, []string{"notebooks/form.tmpl"}, "page:content", data) if err != nil { app.serverError(w, r, err) } err = response.HXFragmentOOB(fullBuf, []string{"notebooks/update_title.tmpl"}, "page:title", data, "page-title") if err != nil { app.serverError(w, r, err) } notebookModel := &models.NotebookModel{DB: app.db} data["notebooksList"] = notebookModel.AllAsOptions(true) err = response.HXFragmentOOB(fullBuf, []string{"partials/notebooks-list.tmpl"}, "partial:notebooks-list", data, "current_notebook_id") if err != nil { app.serverError(w, r, err) } dataMessage := make(map[string]string) dataMessage["messageType"] = "success" dataMessage["messageContent"] = "Notebook created successfully" err = response.HXFragmentOOB(fullBuf, []string{"partials/message.tmpl"}, "message", dataMessage, "message") if err != nil { app.serverError(w, r, err) } w.Header().Add("HX-Replace-Url", fmt.Sprint("/notebook/update/", notebook_id)) fullBuf.WriteTo(w) w.WriteHeader(http.StatusUnprocessableEntity) } } func (app *application) notebookUpdate(w http.ResponseWriter, r *http.Request) { notebookModel := &models.NotebookModel{DB: app.db} notebook_id_str := flow.Param(r.Context(), "notebook_id") notebook_id, _ := strconv.ParseInt(notebook_id_str, 10, 64) notebook, _, _ := notebookModel.One(notebook_id) data := app.newTemplateData(r) data["formAction"] = "/notebook/update/" + notebook_id_str data["formTarget"] = "#message" var fullBuf = new(bytes.Buffer) switch r.Method { case http.MethodGet: data["notebook"] = notebookForm{ Id: notebook.Id, Title: notebook.Title, Icon: notebook.Icon, Description: notebook.Description, } if r.Header.Get("HX-Request") == "true" { err := response.HXFragment(fullBuf, []string{"notebooks/form.tmpl"}, "page:content", data) if err != nil { app.serverError(w, r, err) } err = response.HXFragmentOOB(fullBuf, []string{"notebooks/update_title.tmpl"}, "page:title", data, "page-title") if err != nil { app.serverError(w, r, err) } fullBuf.WriteTo(w) } else { err := response.Page(w, http.StatusOK, data, []string{"notebooks/update_title.tmpl", "notebooks/form.tmpl"}) if err != nil { app.serverError(w, r, err) } } case http.MethodPost: var notebookFromForm notebookForm err := request.DecodePostForm(r, ¬ebookFromForm) if err != nil { app.serverError(w, r, err) } if !notebookFromForm.Validate(w, r, app, data) { return } notebook.Title = notebookFromForm.Title notebook.Description = notebookFromForm.Description notebook.Icon = notebookFromForm.Icon err = notebookModel.Update(notebook) if err != nil { app.badRequest(w, err) return } data["notebook"] = notebookForm{ Id: notebook.Id, Title: notebook.Title, Icon: notebook.Icon, Description: notebook.Description, } dataMessage := make(map[string]string) dataMessage["messageType"] = "success" dataMessage["messageContent"] = "Notebook saved successfully" err = response.HXFragment(fullBuf, []string{"partials/message.tmpl"}, "message", dataMessage) if err != nil { app.serverError(w, r, err) } fullBuf.WriteString("
") err = response.HXFragmentOOB(fullBuf, []string{"notebooks/update_title.tmpl"}, "page:title", data, "page-title") if err != nil { app.serverError(w, r, err) } notebookModel := &models.NotebookModel{DB: app.db} data["notebooksList"] = notebookModel.AllAsOptions(true) err = response.HXFragmentOOB(fullBuf, []string{"partials/notebooks-list.tmpl"}, "partial:notebooks-list", data, "current_notebook_id") if err != nil { app.serverError(w, r, err) } fullBuf.WriteTo(w) w.WriteHeader(http.StatusUnprocessableEntity) } } func (app *application) notebookDelete(w http.ResponseWriter, r *http.Request) { notebookModel := &models.NotebookModel{DB: app.db} notebook_id_str := flow.Param(r.Context(), "notebook_id") notebook_id, _ := strconv.ParseInt(notebook_id_str, 10, 64) _, err := notebookModel.Delete(notebook_id) if err != nil { app.serverError(w, r, err) } }