lets-go:11.0 user signup without peeking
deliberately skipping salting and encrypting passwords at this point. intending to approach this in tandem with authenication. also starting to want db migrations, but trying not to get distracted.
This commit is contained in:
parent
7479313ee8
commit
4f2dc018da
@ -101,3 +101,50 @@ func (app *application) snippetCreatePost(w http.ResponseWriter, r *http.Request
|
||||
|
||||
http.Redirect(w, r, fmt.Sprintf("/snippet/view/%d", id), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
type userSignupForm struct {
|
||||
Username string `form:"username"`
|
||||
Password string `form:"password"`
|
||||
validator.Validator `form:"-"`
|
||||
}
|
||||
|
||||
// userSignup ...
|
||||
func (app *application) userSignup(w http.ResponseWriter, r *http.Request) {
|
||||
data := app.newTemplateData(r)
|
||||
|
||||
data.Form = userSignupForm{}
|
||||
|
||||
app.render(w, r, http.StatusOK, "signup.tmpl", data)
|
||||
}
|
||||
|
||||
|
||||
// userSignup ...
|
||||
func (app *application) userSignupPost(w http.ResponseWriter, r *http.Request) {
|
||||
var form userSignupForm
|
||||
|
||||
err := app.decodePostForm(r, &form)
|
||||
if err != nil {
|
||||
app.clientError(w, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
form.CheckField(validator.NotBlank(form.Username), "username", "This field cannot be blank")
|
||||
form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank")
|
||||
|
||||
if !form.Valid() {
|
||||
data := app.newTemplateData(r)
|
||||
data.Form = form
|
||||
app.render(w, r, http.StatusUnprocessableEntity, "signup.tmpl", data)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := app.users.Insert(form.Username, form.Password)
|
||||
if err != nil {
|
||||
app.serverError(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
app.sessionManager.Put(r.Context(), "flash", fmt.Sprintf("CREATED A USER! (%d)", id))
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
type application struct {
|
||||
logger *slog.Logger
|
||||
snippets *models.SnippetModel
|
||||
users *models.UserModel
|
||||
templateCache map[string]*template.Template
|
||||
formDecoder *form.Decoder
|
||||
sessionManager *scs.SessionManager
|
||||
@ -63,6 +64,7 @@ func main() {
|
||||
app := &application{
|
||||
logger: logger,
|
||||
snippets: &models.SnippetModel{DB: db},
|
||||
users: &models.UserModel{DB: db},
|
||||
templateCache: templateCache,
|
||||
formDecoder: formDecoder,
|
||||
sessionManager: sessionManager,
|
||||
|
@ -29,6 +29,10 @@ func (app *application) routes() http.Handler {
|
||||
router.Handler(http.MethodGet, "/snippet/view/:id", dynamic.ThenFunc(app.snippetView))
|
||||
router.Handler(http.MethodGet, "/snippet/create", dynamic.ThenFunc(app.snippetCreate))
|
||||
router.Handler(http.MethodPost, "/snippet/create", dynamic.ThenFunc(app.snippetCreatePost))
|
||||
router.Handler(http.MethodGet, "/user/signup", dynamic.ThenFunc(app.userSignup))
|
||||
router.Handler(http.MethodPost, "/user/signup", dynamic.ThenFunc(app.userSignupPost))
|
||||
// router.Handler(http.MethodGet, "/user/login", dynamic.ThenFunc(app.userLogin))
|
||||
// router.Handler(http.MethodPost, "/user/login", dynamic.ThenFunc(app.userLoginPost))
|
||||
|
||||
standard := alice.New(app.recoverPanic, app.logRequest, secureHeaders)
|
||||
|
||||
|
@ -20,3 +20,11 @@ CREATE TABLE sessions (
|
||||
);
|
||||
|
||||
CREATE INDEX sessions_expiry_idx on sessions(expiry);
|
||||
|
||||
CREATE TABLE users (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
username VARCHAR(20) NOT NULL,
|
||||
password VARCHAR(20) NOT NULL,
|
||||
created DATETIME NOT NULL,
|
||||
UNIQUE (username)
|
||||
)
|
||||
|
50
snippetbox/internal/models/users.go
Normal file
50
snippetbox/internal/models/users.go
Normal file
@ -0,0 +1,50 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Username string
|
||||
}
|
||||
|
||||
type UserModel struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
// Insert
|
||||
func (m *UserModel) Insert(username string, password string) (int, error) {
|
||||
stmt := `INSERT INTO users (username, password, created)
|
||||
VALUES(?, ?, UTC_TIMESTAMP())`
|
||||
|
||||
result, err := m.DB.Exec(stmt, username, password)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(id), nil
|
||||
}
|
||||
|
||||
// Get
|
||||
func (m *UserModel) Get(id int) (User, error) {
|
||||
stmt := "SELECT id, username FROM users WHERE id = ?"
|
||||
|
||||
var u User
|
||||
|
||||
err := m.DB.QueryRow(stmt, id).Scan(&u.Username)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return User{}, ErrNoRecord
|
||||
} else {
|
||||
return User{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return u, nil
|
||||
}
|
22
snippetbox/ui/html/pages/signup.tmpl
Normal file
22
snippetbox/ui/html/pages/signup.tmpl
Normal file
@ -0,0 +1,22 @@
|
||||
{{define "title"}}User Signup{{end}}
|
||||
|
||||
{{define "main"}}
|
||||
<form action='/user/signup' method='POST'>
|
||||
<div>
|
||||
<label>Username:</label>
|
||||
{{with .Form.FieldErrors.username}}
|
||||
<label class='error'>{{.}}</label>
|
||||
{{end}}
|
||||
<input type='text' name='username' value='{{.Form.Username}}'>
|
||||
</div>
|
||||
<div>
|
||||
<label>Password:</label>
|
||||
{{with .Form.FieldErrors.password}}
|
||||
<label class='error'>{{.}}</label>
|
||||
{{end}}
|
||||
<input type='text' name='password' value='{{.Form.Password}}'>
|
||||
</div>
|
||||
<div>
|
||||
<input type='submit' value='Signup'>
|
||||
</div>
|
||||
{{end}}
|
Loading…
Reference in New Issue
Block a user