added registeration and started user login

This commit is contained in:
Philipp 2021-08-29 19:26:01 +02:00
parent 3f2cbcea33
commit 7ec8dbc211
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: 276B613AF9DBE9C3
14 changed files with 327 additions and 1 deletions

View file

@ -6,6 +6,8 @@ func init() {
gob.Register(CreatePostForm{})
gob.Register(CreateThreadForm{})
gob.Register(CreateCommentForm{})
gob.Register(RegisterForm{})
gob.Register(LoginForm{})
gob.Register(FormErrors{})
}
@ -66,3 +68,53 @@ func (f *CreateCommentForm) Validate() bool {
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
}

View file

@ -22,6 +22,7 @@ func NewHandler(store goddit.Store, sessions *scs.SessionManager, csrfKey []byte
threads := ThreadHandler{store: store, sessions: sessions}
posts := PostHandler{store: store, sessions: sessions}
comments := CommentHandler{store: store, sessions: sessions}
users := UserHandler{store: store, sessions: sessions}
h.Use(middleware.Logger)
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())
})
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
}
@ -70,7 +76,7 @@ func (h *Handler) Home() http.HandlerFunc {
}
once.Do(func() {
h.sessions.Put(r.Context(), "flash", "hello")
h.sessions.Put(r.Context(), "flash", "helloc")
})
tmpl.Execute(w, data{

View file

@ -3,11 +3,17 @@ package web
import (
"context"
"database/sql"
"encoding/gob"
"github.com/alexedwards/scs/postgresstore"
"github.com/alexedwards/scs/v2"
"github.com/google/uuid"
)
func init() {
gob.Register(uuid.UUID{})
}
func NewSessionsManager(dataSourceName string) (*scs.SessionManager, error) {
db, err := sql.Open("postgres", dataSourceName)
if err != nil {

117
web/user_handler.go Normal file
View 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)
}
}