package main import ( "log" "net/http" "strconv" h "gitlab.codemonkeysoftware.net/b/hatmill" ha "gitlab.codemonkeysoftware.net/b/hatmill/attribute" he "gitlab.codemonkeysoftware.net/b/hatmill/element" ) const ( pathRoot = "/" pathCreatePost = "/create-post" pathDoCreatePost = "/create-post/do" ) type handler struct { mux *http.ServeMux store *Store baseURL string } func NewHandler(store *Store, baseURL string) http.Handler { h := &handler{ store: store, mux: http.NewServeMux(), baseURL: baseURL, } h.mux.HandleFunc(pathRoot, h.getPosts) h.mux.HandleFunc(pathCreatePost, h.createPost) h.mux.HandleFunc(pathDoCreatePost, h.doCreatePost) return h } func (hnd *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { hnd.mux.ServeHTTP(w, r) } func (hnd *handler) getPosts(w http.ResponseWriter, r *http.Request) { result, err := hnd.store.GetPosts(r.Context()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } var rows h.Terms for _, post := range result.Posts { rows = append(rows, he.Tr()( he.Td()(h.Text(strconv.FormatInt(post.Id, 10))), he.Td()(h.Text(post.CreatedAt)), he.Td()(h.Text(post.UpdatedAt)), he.Td()(h.Text(post.Author)), he.Td()(h.Text(post.Title)), // he.Td()(h.Text(post.Body)), )) } html := he.Html()( he.Head()(), he.Body()( he.H1()(h.Text("Posts")), he.Table()( he.Thead()( he.Tr()( he.Th()(h.Text("ID")), he.Th()(h.Text("Created")), he.Th()(h.Text("Updated")), he.Th()(h.Text("Author")), he.Th()(h.Text("Title")), ), ), he.Tbody()( rows..., ), ), he.A(ha.Href(hnd.baseURL+pathCreatePost))(h.Text("Create post")), ), ) _, err = h.WriteDocument(w, html) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } const ( fieldNamePostTitle = "post-title" fieldNamePostBody = "post-body" fieldNamePostAuthor = "post-author" ) func (hnd *handler) createPost(w http.ResponseWriter, r *http.Request) { html := he.Html()( he.Head()(), he.Body()( he.H1()(h.Text("Create post")), he.Form(ha.Action(hnd.baseURL+pathDoCreatePost), ha.Method("POST"))( he.Label(ha.For(fieldNamePostTitle))(h.Text("Title")), he.Input(ha.Name(fieldNamePostTitle)), he.Br(), he.Label(ha.For(fieldNamePostAuthor))(h.Text("Author")), he.Input(ha.Name(fieldNamePostAuthor)), he.Br(), he.Label(ha.For(fieldNamePostBody))(h.Text("Body")), he.Textarea(ha.For(fieldNamePostBody))(), he.Br(), he.Input(ha.Type("submit")), ), ), ) _, err := h.WriteDocument(w, html) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } func (hnd *handler) doCreatePost(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } cmd := CreatePostCommand{ Title: r.PostForm.Get(fieldNamePostTitle), Author: r.PostForm.Get(fieldNamePostAuthor), Body: r.PostForm.Get(fieldNamePostBody), } result, err := hnd.store.CreatePost(r.Context(), cmd) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } log.Println("created post", result.PostId) http.Redirect(w, r, pathRoot, http.StatusFound) }