fix panic when submitting invalid form on guestbook page #24
@ -179,9 +179,7 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	form.CheckField(validator.NotBlank(form.AuthorName), "authorName", "This field cannot be blank")
 | 
						form.CheckField(validator.NotBlank(form.AuthorName), "authorName", "This field cannot be blank")
 | 
				
			||||||
	form.CheckField(validator.MaxChars(form.AuthorName, 256), "authorName", "This field cannot be more than 256 characters long")
 | 
						form.CheckField(validator.MaxChars(form.AuthorName, 256), "authorName", "This field cannot be more than 256 characters long")
 | 
				
			||||||
	form.CheckField(validator.NotBlank(form.AuthorEmail), "authorEmail", "This field cannot be blank")
 | 
					 | 
				
			||||||
	form.CheckField(validator.MaxChars(form.AuthorEmail, 256), "authorEmail", "This field cannot be more than 256 characters long")
 | 
						form.CheckField(validator.MaxChars(form.AuthorEmail, 256), "authorEmail", "This field cannot be more than 256 characters long")
 | 
				
			||||||
	form.CheckField(validator.NotBlank(form.AuthorSite), "authorSite", "This field cannot be blank")
 | 
					 | 
				
			||||||
	form.CheckField(validator.MaxChars(form.AuthorSite, 256), "authorSite", "This field cannot be more than 256 characters long")
 | 
						form.CheckField(validator.MaxChars(form.AuthorSite, 256), "authorSite", "This field cannot be more than 256 characters long")
 | 
				
			||||||
	form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")
 | 
						form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -193,7 +191,8 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		data := app.newCommonData(r)
 | 
							data := app.newCommonData(r)
 | 
				
			||||||
		views.GuestbookView("Guestbook", data, website, website.Guestbook, comments, forms.CommentCreateForm{}).Render(r.Context(), w)
 | 
							w.WriteHeader(http.StatusUnprocessableEntity)
 | 
				
			||||||
 | 
							views.GuestbookView("Guestbook", data, website, website.Guestbook, comments, form).Render(r.Context(), w)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -203,7 +202,7 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt
 | 
				
			|||||||
		app.serverError(w, r, err)
 | 
							app.serverError(w, r, err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// app.sessionManager.Put(r.Context(), "flash", "Comment successfully posted!")
 | 
						app.sessionManager.Put(r.Context(), "flash", "Comment successfully posted!")
 | 
				
			||||||
	http.Redirect(w, r, fmt.Sprintf("/websites/%s/guestbook", slug), http.StatusSeeOther)
 | 
						http.Redirect(w, r, fmt.Sprintf("/websites/%s/guestbook", slug), http.StatusSeeOther)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ package main
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.32bit.cafe/32bitcafe/guestbook/internal/assert"
 | 
						"git.32bit.cafe/32bitcafe/guestbook/internal/assert"
 | 
				
			||||||
@ -58,3 +59,88 @@ func TestGetGuestbookView(t *testing.T) {
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPostGuestbookCommentCreate(t *testing.T) {
 | 
				
			||||||
 | 
						app := newTestApplication(t)
 | 
				
			||||||
 | 
						ts := newTestServer(t, app.routes())
 | 
				
			||||||
 | 
						defer ts.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, _, body := ts.get(t, fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(1)))
 | 
				
			||||||
 | 
						validCSRFToken := extractCSRFToken(t, body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const (
 | 
				
			||||||
 | 
							validAuthorName  = "John Test"
 | 
				
			||||||
 | 
							validAuthorEmail = "test@example.com"
 | 
				
			||||||
 | 
							validAuthorSite  = "example.com"
 | 
				
			||||||
 | 
							validContent     = "This is a comment"
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name        string
 | 
				
			||||||
 | 
							authorName  string
 | 
				
			||||||
 | 
							authorEmail string
 | 
				
			||||||
 | 
							authorSite  string
 | 
				
			||||||
 | 
							content     string
 | 
				
			||||||
 | 
							csrfToken   string
 | 
				
			||||||
 | 
							wantCode    int
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:        "Valid input",
 | 
				
			||||||
 | 
								authorName:  validAuthorName,
 | 
				
			||||||
 | 
								authorEmail: validAuthorEmail,
 | 
				
			||||||
 | 
								authorSite:  validAuthorSite,
 | 
				
			||||||
 | 
								content:     validContent,
 | 
				
			||||||
 | 
								csrfToken:   validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:    http.StatusSeeOther,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:        "Blank name",
 | 
				
			||||||
 | 
								authorName:  "",
 | 
				
			||||||
 | 
								authorEmail: validAuthorEmail,
 | 
				
			||||||
 | 
								authorSite:  validAuthorSite,
 | 
				
			||||||
 | 
								content:     validContent,
 | 
				
			||||||
 | 
								csrfToken:   validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:    http.StatusUnprocessableEntity,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:        "Blank email",
 | 
				
			||||||
 | 
								authorName:  validAuthorName,
 | 
				
			||||||
 | 
								authorEmail: "",
 | 
				
			||||||
 | 
								authorSite:  validAuthorSite,
 | 
				
			||||||
 | 
								content:     validContent,
 | 
				
			||||||
 | 
								csrfToken:   validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:    http.StatusSeeOther,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:        "Blank site",
 | 
				
			||||||
 | 
								authorName:  validAuthorName,
 | 
				
			||||||
 | 
								authorEmail: validAuthorEmail,
 | 
				
			||||||
 | 
								authorSite:  "",
 | 
				
			||||||
 | 
								content:     validContent,
 | 
				
			||||||
 | 
								csrfToken:   validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:    http.StatusSeeOther,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:        "Blank content",
 | 
				
			||||||
 | 
								authorName:  validAuthorName,
 | 
				
			||||||
 | 
								authorEmail: validAuthorEmail,
 | 
				
			||||||
 | 
								authorSite:  validAuthorSite,
 | 
				
			||||||
 | 
								content:     "",
 | 
				
			||||||
 | 
								csrfToken:   validCSRFToken,
 | 
				
			||||||
 | 
								wantCode:    http.StatusUnprocessableEntity,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, tt := range tests {
 | 
				
			||||||
 | 
							t.Run(tt.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								form := url.Values{}
 | 
				
			||||||
 | 
								form.Add("authorname", tt.authorName)
 | 
				
			||||||
 | 
								form.Add("authoremail", tt.authorEmail)
 | 
				
			||||||
 | 
								form.Add("authorsite", tt.authorSite)
 | 
				
			||||||
 | 
								form.Add("content", tt.content)
 | 
				
			||||||
 | 
								form.Add("csrf_token", tt.csrfToken)
 | 
				
			||||||
 | 
								code, _, body := ts.postForm(t, fmt.Sprintf("/websites/%s/guestbook/comments/create", shortIdToSlug(1)), form)
 | 
				
			||||||
 | 
								assert.Equal(t, code, tt.wantCode)
 | 
				
			||||||
 | 
								assert.Equal(t, body, body)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ func (app *application) routes() http.Handler {
 | 
				
			|||||||
	standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders)
 | 
						standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mux.Handle("/{$}", dynamic.ThenFunc(app.home))
 | 
						mux.Handle("/{$}", dynamic.ThenFunc(app.home))
 | 
				
			||||||
	mux.Handle("POST /websites/{id}/guestbook/comments/create", standard.ThenFunc(app.postGuestbookCommentCreate))
 | 
						mux.Handle("POST /websites/{id}/guestbook/comments/create", dynamic.ThenFunc(app.postGuestbookCommentCreate))
 | 
				
			||||||
	mux.Handle("GET /websites/{id}/guestbook", dynamic.ThenFunc(app.getGuestbook))
 | 
						mux.Handle("GET /websites/{id}/guestbook", dynamic.ThenFunc(app.getGuestbook))
 | 
				
			||||||
	mux.Handle("GET /users/register", dynamic.ThenFunc(app.getUserRegister))
 | 
						mux.Handle("GET /users/register", dynamic.ThenFunc(app.getUserRegister))
 | 
				
			||||||
	mux.Handle("POST /users/register", dynamic.ThenFunc(app.postUserRegister))
 | 
						mux.Handle("POST /users/register", dynamic.ThenFunc(app.postUserRegister))
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ type CommentCreateForm struct {
 | 
				
			|||||||
	AuthorName          string `schema:"authorname"`
 | 
						AuthorName          string `schema:"authorname"`
 | 
				
			||||||
	AuthorEmail         string `schema:"authoremail"`
 | 
						AuthorEmail         string `schema:"authoremail"`
 | 
				
			||||||
	AuthorSite          string `schema:"authorsite"`
 | 
						AuthorSite          string `schema:"authorsite"`
 | 
				
			||||||
	Content             string `schema:"content,required"`
 | 
						Content             string `schema:"content"`
 | 
				
			||||||
	validator.Validator `schema:"-"`
 | 
						validator.Validator `schema:"-"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user