added registeration and started user login
This commit is contained in:
parent
3f2cbcea33
commit
7ec8dbc211
14 changed files with 327 additions and 1 deletions
1
go.mod
1
go.mod
|
@ -10,4 +10,5 @@ require (
|
||||||
github.com/gorilla/csrf v1.7.1 // indirect
|
github.com/gorilla/csrf v1.7.1 // indirect
|
||||||
github.com/jmoiron/sqlx v1.3.4 // indirect
|
github.com/jmoiron/sqlx v1.3.4 // indirect
|
||||||
github.com/lib/pq v1.10.2 // indirect
|
github.com/lib/pq v1.10.2 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||||
)
|
)
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -33,5 +33,13 @@ github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750=
|
||||||
github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g=
|
github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|
14
goddit.go
14
goddit.go
|
@ -25,6 +25,11 @@ type Comment struct {
|
||||||
Votes int `db:"votes"`
|
Votes int `db:"votes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID uuid.UUID `db:"id"`
|
||||||
|
Username string `db:"username"`
|
||||||
|
Password string `db:"password"`
|
||||||
|
}
|
||||||
type ThreadStore interface {
|
type ThreadStore interface {
|
||||||
Thread(id uuid.UUID) (Thread, error)
|
Thread(id uuid.UUID) (Thread, error)
|
||||||
Threads() ([]Thread, error)
|
Threads() ([]Thread, error)
|
||||||
|
@ -50,8 +55,17 @@ type CommentStore interface {
|
||||||
DeleteComment(id uuid.UUID) error
|
DeleteComment(id uuid.UUID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserStore interface {
|
||||||
|
User(id uuid.UUID) (User, error)
|
||||||
|
UserByUsername(username string) (User, error)
|
||||||
|
CreateUser(u *User) error
|
||||||
|
UpdateUser(u *User) error
|
||||||
|
DeleteUser(id uuid.UUID) error
|
||||||
|
}
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
ThreadStore
|
ThreadStore
|
||||||
PostStore
|
PostStore
|
||||||
CommentStore
|
CommentStore
|
||||||
|
UserStore
|
||||||
}
|
}
|
||||||
|
|
1
migrations/3_create_users_table.down.sql
Normal file
1
migrations/3_create_users_table.down.sql
Normal file
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE users;
|
5
migrations/3_create_users_table.up.sql
Normal file
5
migrations/3_create_users_table.up.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
CREATE TABLE users (
|
||||||
|
id UUID PRIMARY KEY,
|
||||||
|
username TEXT NOT NULL UNIQUE,
|
||||||
|
password TEXT NOT NULL
|
||||||
|
);
|
|
@ -20,6 +20,7 @@ func NewStore(dataSourceName string) (*Store, error) {
|
||||||
ThreadStore: &ThreadStore{DB: db},
|
ThreadStore: &ThreadStore{DB: db},
|
||||||
PostStore: &PostStore{DB: db},
|
PostStore: &PostStore{DB: db},
|
||||||
CommentStore: &CommentStore{DB: db},
|
CommentStore: &CommentStore{DB: db},
|
||||||
|
UserStore: &UserStore{DB: db},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,4 +28,5 @@ type Store struct {
|
||||||
*ThreadStore
|
*ThreadStore
|
||||||
*PostStore
|
*PostStore
|
||||||
*CommentStore
|
*CommentStore
|
||||||
|
*UserStore
|
||||||
}
|
}
|
||||||
|
|
64
postgres/user_store.go
Normal file
64
postgres/user_store.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.snrd.de/Spaenny/goddit"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserStore struct {
|
||||||
|
*sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserStore) User(id uuid.UUID) (goddit.User, error) {
|
||||||
|
var u goddit.User
|
||||||
|
if err := s.Get(&u, `SELECT * FROM users WHERE id = $1`, id); err != nil {
|
||||||
|
return goddit.User{}, fmt.Errorf("error getting user: %w", err)
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserStore) UserByUsername(username string) (goddit.User, error) {
|
||||||
|
var u goddit.User
|
||||||
|
if err := s.Get(&u, `SELECT * FROM users WHERE username = $1`, username); err != nil {
|
||||||
|
return goddit.User{}, fmt.Errorf("error getting user: %w", err)
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserStore) Users() ([]goddit.User, error) {
|
||||||
|
var uu []goddit.User
|
||||||
|
if err := s.Select(&uu, `SELECT * FROM users`); err != nil {
|
||||||
|
return []goddit.User{}, fmt.Errorf("error getting users: %w", err)
|
||||||
|
}
|
||||||
|
return uu, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserStore) CreateUser(u *goddit.User) error {
|
||||||
|
if err := s.Get(u, `INSERT INTO users VALUES($1, $2, $3) RETURNING *`,
|
||||||
|
u.ID,
|
||||||
|
u.Username,
|
||||||
|
u.Password); err != nil {
|
||||||
|
return fmt.Errorf("error creating user: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserStore) UpdateUser(u *goddit.User) error {
|
||||||
|
if err := s.Get(u, `UPDATE INTO users SET username = $1, password = $2 WHERE id = $3) RETURNING *`,
|
||||||
|
u.Username,
|
||||||
|
u.Password,
|
||||||
|
u.ID); err != nil {
|
||||||
|
return fmt.Errorf("error updating user: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserStore) DeleteUser(id uuid.UUID) error {
|
||||||
|
if _, err := s.Exec(`DELETE FROM users WHERE id = $1`, id); err != nil {
|
||||||
|
return fmt.Errorf("error deleteing user: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -12,6 +12,8 @@
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-light container">
|
<nav class="navbar navbar-light container">
|
||||||
<a class="navbar-brand text-primary" href="/">goddit</a>
|
<a class="navbar-brand text-primary" href="/">goddit</a>
|
||||||
|
<div class="flex-fill"></div>
|
||||||
|
<a class="text-primary text-primary" href="/register">Register</a>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="header bg-light border-bottom border-top py-5">
|
<div class="header bg-light border-bottom border-top py-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
24
templates/user_login.html
Normal file
24
templates/user_login.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{{define "header"}}
|
||||||
|
<h1 class="mb-0">Register</h1>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
<form action="/login" method="POST">
|
||||||
|
{{.CSRF}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Username</label>
|
||||||
|
<input name="username" type="text" class="form-control {{with .Form.Errors.Title}}is-invalid{{end}}" placeholder="Enter your username" value="{{with .Form.Username}}{{.}}{{end}}">
|
||||||
|
{{with .Form.Errors.Username}}
|
||||||
|
<div class="invalid-feedack">{{.}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Password</label>
|
||||||
|
<input name="password" type="password" class="form-control {{with .Form.Errors.Password}}is-invalid{{end}}" placeholder="Enter your password" value="{{with .Form.Password}}{{.}}{{end}}">
|
||||||
|
{{with .Form.Errors.Password}}
|
||||||
|
<div class="invalid-feedack">{{.}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Login</button>
|
||||||
|
</form>
|
||||||
|
{{end}}
|
24
templates/user_register.html
Normal file
24
templates/user_register.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{{define "header"}}
|
||||||
|
<h1 class="mb-0">Register</h1>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
<form action="/register" method="POST">
|
||||||
|
{{.CSRF}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Username</label>
|
||||||
|
<input name="username" type="text" class="form-control {{with .Form.Errors.Title}}is-invalid{{end}}" placeholder="Choose a username" value="{{with .Form.Username}}{{.}}{{end}}">
|
||||||
|
{{with .Form.Errors.Username}}
|
||||||
|
<div class="invalid-feedack">{{.}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Password</label>
|
||||||
|
<input name="password" type="password" class="form-control {{with .Form.Errors.Password}}is-invalid{{end}}" placeholder="Please enter your password" value="{{with .Form.Password}}{{.}}{{end}}">
|
||||||
|
{{with .Form.Errors.Password}}
|
||||||
|
<div class="invalid-feedack">{{.}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Register</button>
|
||||||
|
</form>
|
||||||
|
{{end}}
|
52
web/forms.go
52
web/forms.go
|
@ -6,6 +6,8 @@ func init() {
|
||||||
gob.Register(CreatePostForm{})
|
gob.Register(CreatePostForm{})
|
||||||
gob.Register(CreateThreadForm{})
|
gob.Register(CreateThreadForm{})
|
||||||
gob.Register(CreateCommentForm{})
|
gob.Register(CreateCommentForm{})
|
||||||
|
gob.Register(RegisterForm{})
|
||||||
|
gob.Register(LoginForm{})
|
||||||
gob.Register(FormErrors{})
|
gob.Register(FormErrors{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,3 +68,53 @@ func (f *CreateCommentForm) Validate() bool {
|
||||||
|
|
||||||
return len(f.Errors) == 0
|
return len(f.Errors) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RegisterForm struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
UsernameTaken bool
|
||||||
|
|
||||||
|
Errors FormErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *RegisterForm) Validate() bool {
|
||||||
|
f.Errors = FormErrors{}
|
||||||
|
|
||||||
|
if f.Username == "" {
|
||||||
|
f.Errors["Username"] = "Please enter a username!"
|
||||||
|
} else if f.UsernameTaken {
|
||||||
|
f.Errors["Username"] = "This username is already taken!"
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.Password == "" {
|
||||||
|
f.Errors["Password"] = "Please enter a password!"
|
||||||
|
} else if len(f.Password) < 8 {
|
||||||
|
f.Errors["Password"] = "Your password must be at least 8 charachters long."
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(f.Errors) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginForm struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
IncorrectCredentials bool
|
||||||
|
|
||||||
|
Errors FormErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *LoginForm) Validate() bool {
|
||||||
|
f.Errors = FormErrors{}
|
||||||
|
|
||||||
|
if f.Username == "" {
|
||||||
|
f.Errors["Username"] = "Please enter a username!"
|
||||||
|
} else if f.IncorrectCredentials {
|
||||||
|
f.Errors["Username"] = "Username or password is incorrect."
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.Password == "" {
|
||||||
|
f.Errors["Password"] = "Please enter a password!"
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(f.Errors) == 0
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ func NewHandler(store goddit.Store, sessions *scs.SessionManager, csrfKey []byte
|
||||||
threads := ThreadHandler{store: store, sessions: sessions}
|
threads := ThreadHandler{store: store, sessions: sessions}
|
||||||
posts := PostHandler{store: store, sessions: sessions}
|
posts := PostHandler{store: store, sessions: sessions}
|
||||||
comments := CommentHandler{store: store, sessions: sessions}
|
comments := CommentHandler{store: store, sessions: sessions}
|
||||||
|
users := UserHandler{store: store, sessions: sessions}
|
||||||
|
|
||||||
h.Use(middleware.Logger)
|
h.Use(middleware.Logger)
|
||||||
h.Use(csrf.Protect(csrfKey, csrf.Secure(false)))
|
h.Use(csrf.Protect(csrfKey, csrf.Secure(false)))
|
||||||
|
@ -41,6 +42,11 @@ func NewHandler(store goddit.Store, sessions *scs.SessionManager, csrfKey []byte
|
||||||
r.Post("/{threadID}/{postID}", comments.Store())
|
r.Post("/{threadID}/{postID}", comments.Store())
|
||||||
})
|
})
|
||||||
h.Get("/comments/{id}/vote", comments.Vote())
|
h.Get("/comments/{id}/vote", comments.Vote())
|
||||||
|
h.Get("/register", users.Register())
|
||||||
|
h.Post("/register", users.RegisterSubmit())
|
||||||
|
h.Get("/login", users.Login())
|
||||||
|
h.Post("/login", users.LoginSubmit())
|
||||||
|
h.Get("/logout", users.Logout())
|
||||||
|
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
@ -70,7 +76,7 @@ func (h *Handler) Home() http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
h.sessions.Put(r.Context(), "flash", "hello")
|
h.sessions.Put(r.Context(), "flash", "helloc")
|
||||||
})
|
})
|
||||||
|
|
||||||
tmpl.Execute(w, data{
|
tmpl.Execute(w, data{
|
||||||
|
|
|
@ -3,11 +3,17 @@ package web
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/gob"
|
||||||
|
|
||||||
"github.com/alexedwards/scs/postgresstore"
|
"github.com/alexedwards/scs/postgresstore"
|
||||||
"github.com/alexedwards/scs/v2"
|
"github.com/alexedwards/scs/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register(uuid.UUID{})
|
||||||
|
}
|
||||||
|
|
||||||
func NewSessionsManager(dataSourceName string) (*scs.SessionManager, error) {
|
func NewSessionsManager(dataSourceName string) (*scs.SessionManager, error) {
|
||||||
db, err := sql.Open("postgres", dataSourceName)
|
db, err := sql.Open("postgres", dataSourceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
117
web/user_handler.go
Normal file
117
web/user_handler.go
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.snrd.de/Spaenny/goddit"
|
||||||
|
"github.com/alexedwards/scs/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/gorilla/csrf"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserHandler struct {
|
||||||
|
store goddit.Store
|
||||||
|
sessions *scs.SessionManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *UserHandler) Register() http.HandlerFunc {
|
||||||
|
type data struct {
|
||||||
|
SessionData
|
||||||
|
|
||||||
|
CSRF template.HTML
|
||||||
|
}
|
||||||
|
tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/user_register.html"))
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tmpl.Execute(w, data{
|
||||||
|
SessionData: GetSessionData(h.sessions, r.Context()),
|
||||||
|
CSRF: csrf.TemplateField(r),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *UserHandler) RegisterSubmit() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
form := RegisterForm{
|
||||||
|
Username: r.FormValue("username"),
|
||||||
|
Password: r.FormValue("password"),
|
||||||
|
UsernameTaken: false,
|
||||||
|
}
|
||||||
|
if _, err := h.store.UserByUsername(form.Username); err == nil {
|
||||||
|
form.UsernameTaken = true
|
||||||
|
}
|
||||||
|
if !form.Validate() {
|
||||||
|
h.sessions.Put(r.Context(), "form", form)
|
||||||
|
http.Redirect(w, r, r.Referer(), http.StatusFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := bcrypt.GenerateFromPassword([]byte(form.Password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.store.CreateUser(&goddit.User{
|
||||||
|
ID: uuid.New(),
|
||||||
|
Username: form.Username,
|
||||||
|
Password: string(password),
|
||||||
|
}); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.sessions.Put(r.Context(), "flash", "Your registration was successful. Please log in.")
|
||||||
|
http.Redirect(w, r, "/", http.StatusFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *UserHandler) Login() http.HandlerFunc {
|
||||||
|
type data struct {
|
||||||
|
SessionData
|
||||||
|
|
||||||
|
CSRF template.HTML
|
||||||
|
}
|
||||||
|
tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/user_login.html"))
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tmpl.Execute(w, data{
|
||||||
|
SessionData: GetSessionData(h.sessions, r.Context()),
|
||||||
|
CSRF: csrf.TemplateField(r),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *UserHandler) LoginSubmit() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
form := LoginForm{
|
||||||
|
Username: r.FormValue("username"),
|
||||||
|
Password: r.FormValue("password"),
|
||||||
|
IncorrectCredentials: false,
|
||||||
|
}
|
||||||
|
user, err := h.store.UserByUsername(form.Username)
|
||||||
|
if err == nil {
|
||||||
|
form.IncorrectCredentials = true
|
||||||
|
} else {
|
||||||
|
compareErr := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(form.Password))
|
||||||
|
form.IncorrectCredentials = compareErr != nil
|
||||||
|
}
|
||||||
|
if !form.Validate() {
|
||||||
|
h.sessions.Put(r.Context(), "form", form)
|
||||||
|
http.Redirect(w, r, r.Referer(), http.StatusFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.sessions.Put(r.Context(), "user_id", user.ID)
|
||||||
|
h.sessions.Put(r.Context(), "flash", "You have been logged in successfully.")
|
||||||
|
http.Redirect(w, r, "/", http.StatusFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *UserHandler) Logout() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h.sessions.Remove(r.Context(), "user_id")
|
||||||
|
h.sessions.Put(r.Context(), "flash", "You have been logged out successfully.")
|
||||||
|
http.Redirect(w, r, "/", http.StatusFound)
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue