Added basic login functionality to login form
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.env
|
||||
tmp/
|
||||
projectreshoot
|
||||
static/css/output.css
|
||||
|
||||
36
cookies/pagefrom.go
Normal file
36
cookies/pagefrom.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package cookies
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CheckPageFrom(w http.ResponseWriter, r *http.Request) string {
|
||||
pageFromCookie, err := r.Cookie("pagefrom")
|
||||
if err != nil {
|
||||
return "/"
|
||||
}
|
||||
pageFrom := pageFromCookie.Value
|
||||
deleteCookie := &http.Cookie{Name: "pagefrom", Value: "", Expires: time.Unix(0, 0)}
|
||||
http.SetCookie(w, deleteCookie)
|
||||
return pageFrom
|
||||
}
|
||||
|
||||
func SetPageFrom(w http.ResponseWriter, r *http.Request) {
|
||||
referer := r.Referer()
|
||||
parsedURL, err := url.Parse(referer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var pageFrom string
|
||||
expectedHost := os.Getenv("TRUSTED_HOST")
|
||||
if parsedURL.Path == "" || parsedURL.Host != expectedHost {
|
||||
pageFrom = "/"
|
||||
} else {
|
||||
pageFrom = parsedURL.Path
|
||||
}
|
||||
pageFromCookie := &http.Cookie{Name: "pagefrom", Value: pageFrom}
|
||||
http.SetCookie(w, pageFromCookie)
|
||||
}
|
||||
5
go.mod
5
go.mod
@@ -2,4 +2,7 @@ module projectreshoot
|
||||
|
||||
go 1.23.5
|
||||
|
||||
require github.com/a-h/templ v0.3.833
|
||||
require (
|
||||
github.com/a-h/templ v0.3.833
|
||||
github.com/joho/godotenv v1.5.1
|
||||
)
|
||||
|
||||
2
go.sum
2
go.sum
@@ -2,3 +2,5 @@ github.com/a-h/templ v0.3.833 h1:L/KOk/0VvVTBegtE0fp2RJQiBm7/52Zxv5fqlEHiQUU=
|
||||
github.com/a-h/templ v0.3.833/go.mod h1:cAu4AiZhtJfBjMY0HASlyzvkrtjnHWPeEsyGK2YYmfk=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
|
||||
75
handlers/login.go
Normal file
75
handlers/login.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"projectreshoot/cookies"
|
||||
"projectreshoot/view/component/form"
|
||||
"projectreshoot/view/page"
|
||||
)
|
||||
|
||||
// TODO: here for testing only, move to database
|
||||
type User struct {
|
||||
id int
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
// TODO: here for testing only, move to database
|
||||
func testUser() User {
|
||||
return User{id: 1, username: "Haelnorr", password: "test"}
|
||||
}
|
||||
|
||||
func validateLogin(r *http.Request) (int, error) {
|
||||
formUsername := r.FormValue("username")
|
||||
formPassword := r.FormValue("password")
|
||||
// TODO: search database for username
|
||||
validUser := testUser()
|
||||
// TODO: check password is valid
|
||||
if formUsername != validUser.username || formPassword != validUser.password {
|
||||
return 0, errors.New("Username or password incorrect")
|
||||
}
|
||||
// TODO: return the users ID
|
||||
return validUser.id, nil
|
||||
}
|
||||
|
||||
func checkRememberMe(r *http.Request) bool {
|
||||
rememberMe := r.FormValue("remember-me")
|
||||
if rememberMe == "on" {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func HandleLoginRequest() http.Handler {
|
||||
return http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
userID, err := validateLogin(r)
|
||||
if err != nil {
|
||||
// TODO: add debug log
|
||||
fmt.Printf("Login failed: %s\n", err)
|
||||
form.LoginForm(err.Error()).Render(r.Context(), w)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: login success, use the userID to set the session
|
||||
rememberMe := checkRememberMe(r)
|
||||
fmt.Printf("Login success, user ID: %v - remember me?: %t\n", userID, rememberMe)
|
||||
|
||||
pageFrom := cookies.CheckPageFrom(w, r)
|
||||
w.Header().Set("HX-Redirect", pageFrom)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func HandleLoginPage() http.Handler {
|
||||
return http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
cookies.SetPageFrom(w, r)
|
||||
page.Login().Render(r.Context(), w)
|
||||
},
|
||||
)
|
||||
}
|
||||
5
main.go
5
main.go
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"embed"
|
||||
"fmt"
|
||||
"github.com/joho/godotenv"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -57,6 +58,10 @@ func run(ctx context.Context, w io.Writer) error {
|
||||
var static embed.FS
|
||||
|
||||
func main() {
|
||||
err := godotenv.Load(".env")
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
ctx := context.Background()
|
||||
if err := run(ctx, os.Stdout); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
|
||||
@@ -9,8 +9,16 @@ import (
|
||||
func addRoutes(
|
||||
mux *http.ServeMux,
|
||||
) {
|
||||
// Static files
|
||||
mux.Handle("GET /static/", http.StripPrefix("/static/", handlers.HandleStatic()))
|
||||
|
||||
// Index page
|
||||
mux.Handle("GET /", handlers.HandleRoot())
|
||||
|
||||
// Static pages
|
||||
mux.Handle("GET /about", handlers.HandlePage(page.About()))
|
||||
mux.Handle("GET /login", handlers.HandlePage(page.Login()))
|
||||
|
||||
// Login page and handlers
|
||||
mux.Handle("GET /login", handlers.HandleLoginPage())
|
||||
mux.Handle("POST /login", handlers.HandleLoginRequest())
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import "fmt"
|
||||
templ LoginForm(loginError string) {
|
||||
{{
|
||||
var errCreds string
|
||||
if loginError == "Username or password is incorrect" {
|
||||
if loginError == "Username or password incorrect" {
|
||||
errCreds = "true"
|
||||
} else {
|
||||
errCreds = "false"
|
||||
}
|
||||
xdata := fmt.Sprintf("{credentialError: %s, errorMessage: '%s'}", errCreds, loginError)
|
||||
}}
|
||||
<form>
|
||||
<form hx-post="/login">
|
||||
<div
|
||||
class="grid gap-y-4"
|
||||
x-data={ xdata }
|
||||
@@ -26,7 +26,7 @@ templ LoginForm(loginError string) {
|
||||
<div class="relative">
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
idnutanix="username"
|
||||
name="username"
|
||||
class="py-3 px-4 block w-full rounded-lg text-sm
|
||||
focus:border-blue focus:ring-blue bg-base
|
||||
@@ -65,6 +65,7 @@ templ LoginForm(loginError string) {
|
||||
text-blue decoration-2 hover:underline
|
||||
focus:outline-none focus:underline font-medium"
|
||||
href="/recover-account"
|
||||
tabindex="-1"
|
||||
>Forgot password?</a>
|
||||
</div>
|
||||
<div class="relative">
|
||||
|
||||
@@ -5,7 +5,7 @@ import "projectreshoot/view/layout"
|
||||
templ Error(code string, err string, message string) {
|
||||
@layout.Global() {
|
||||
<div
|
||||
class="grid absolute left-0 right-0 top-0 bottom-0 z-[-1]
|
||||
class="grid mt-24 left-0 right-0 top-0 bottom-0
|
||||
place-content-center bg-base px-4"
|
||||
>
|
||||
<div class="text-center">
|
||||
@@ -22,7 +22,7 @@ templ Error(code string, err string, message string) {
|
||||
<a
|
||||
href="/"
|
||||
class="mt-6 inline-block rounded-lg bg-mauve px-5 py-3
|
||||
text-sm text-crust hover:bg-mauve/75"
|
||||
text-sm text-crust transition hover:bg-mauve/75"
|
||||
>Go to homepage</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user