Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 16 additions & 31 deletions internal/infra/http/api/login.go
Original file line number Diff line number Diff line change
@@ -1,52 +1,37 @@
package api

import (
"bytes"
"encoding/json"
"io"
"net/http"

"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
)

// isHTMXRequest checks if the request is from HTMX
func isHTMXRequest(r *http.Request) bool {
return r.Header.Get("HX-Request") == "true"
}

func (h *Router) login(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
body, err := io.ReadAll(r.Body)
if err != nil {
log.WithError(err).Error("login: failed to read request body")
_ = BadRequest(w, "invalid request body")
return
}
// Restore the body for later use by toLoginCommand
r.Body = io.NopCloser(bytes.NewBuffer(body))

log.WithField("body", string(body)).Info("login: received request")
command, err := toLoginCommand(w, r, nil)
if err != nil {
return
}

response, err := h.authService.Login(command)
if err != nil {
if isHTMXRequest(r) {
// Return HTML error for HTMX requests
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte(`<div class="error-message">Invalid email or password</div>`))
} else {
_ = BadRequest(w, err.Error())
}
_ = BadRequest(w, err.Error())
return
}

if isHTMXRequest(r) {
// For HTMX: Store token in cookie and redirect
http.SetCookie(w, &http.Cookie{
Name: "authToken",
Value: response.AccessToken,
Path: "/",
HttpOnly: false, // JavaScript needs to read it
Secure: false,
SameSite: http.SameSiteLaxMode,
MaxAge: 3600 * 24 * 7, // 7 days
})
w.Header().Set("HX-Redirect", "/")
w.WriteHeader(http.StatusOK)
} else {
// JSON API response
w.WriteHeader(http.StatusOK)
_ = json.NewEncoder(w).Encode(response)
}
w.WriteHeader(http.StatusOK)
_ = json.NewEncoder(w).Encode(response)
}
23 changes: 0 additions & 23 deletions internal/infra/http/api/logout.go

This file was deleted.

46 changes: 8 additions & 38 deletions internal/infra/http/api/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,25 +242,10 @@ func (r *LoginRequest) Validate() error {

func toLoginCommand(w http.ResponseWriter, r *http.Request, _ httprouter.Params) (*auth.LoginCommand, error) {
request := &LoginRequest{}

// Check if this is a form submission (HTMX) or JSON request
contentType := r.Header.Get("Content-Type")
if isHTMXRequest(r) || contentType == "application/x-www-form-urlencoded" || contentType == "multipart/form-data" {
// Parse form data
if err := r.ParseForm(); err != nil {
log.WithError(err).Error("login: failed to parse form data")
_ = BadRequest(w, "invalid request body")
return nil, err
}
request.Email = r.FormValue("email")
request.Password = r.FormValue("password")
} else {
// Parse JSON
if err := json.NewDecoder(r.Body).Decode(request); err != nil {
log.WithError(err).Error("login: failed to decode request body")
_ = BadRequest(w, "invalid request body")
return nil, err
}
if err := json.NewDecoder(r.Body).Decode(request); err != nil {
log.WithError(err).Error("login: failed to decode request body")
_ = BadRequest(w, "invalid request body")
return nil, err
}

if err := request.Validate(); err != nil {
Expand Down Expand Up @@ -289,25 +274,10 @@ func (r *SignupRequest) Validate() error {

func toSignupCommand(w http.ResponseWriter, r *http.Request, _ httprouter.Params) (*auth.SignupCommand, error) {
request := &SignupRequest{}

// Check if this is a form submission (HTMX) or JSON request
contentType := r.Header.Get("Content-Type")
if isHTMXRequest(r) || contentType == "application/x-www-form-urlencoded" || contentType == "multipart/form-data" {
// Parse form data
if err := r.ParseForm(); err != nil {
log.WithError(err).Error("signup: failed to parse form data")
_ = BadRequest(w, "invalid request body")
return nil, err
}
request.Email = r.FormValue("email")
request.Password = r.FormValue("password")
} else {
// Parse JSON
if err := json.NewDecoder(r.Body).Decode(request); err != nil {
log.WithError(err).Error("signup: failed to decode request body")
_ = BadRequest(w, "invalid request body")
return nil, err
}
if err := json.NewDecoder(r.Body).Decode(request); err != nil {
log.WithError(err).Error("signup: failed to decode request body")
_ = BadRequest(w, "invalid request body")
return nil, err
}

if err := request.Validate(); err != nil {
Expand Down
1 change: 0 additions & 1 deletion internal/infra/http/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ func New(itemService ItemService, feedService FeedService, authService AuthServi

router.POST("/login", chain.Wrap(h.login))
router.POST("/signup", chain.Wrap(h.signup))
router.POST("/logout", chain.Wrap(h.logout))
// serve static files for GET /
router.NotFound = http.FileServer(http.Dir("public"))

Expand Down
30 changes: 14 additions & 16 deletions internal/infra/http/api/signup.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
package api

import (
"bytes"
"io"
"net/http"

"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
)

func (h *Router) signup(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
body, err := io.ReadAll(r.Body)
if err != nil {
log.WithError(err).Error("signup: failed to read request body")
_ = BadRequest(w, "invalid request body")
return
}
r.Body = io.NopCloser(bytes.NewBuffer(body))

log.WithField("body", string(body)).Info("signup: received request")
command, err := toSignupCommand(w, r, nil)
if err != nil {
return
}

if err := h.authService.Signup(command); err != nil {
if isHTMXRequest(r) {
// Return HTML error for HTMX requests
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(`<div class="error-message">Error creating account. Email may already be registered.</div>`))
} else {
_ = BadRequest(w, err.Error())
}
_ = BadRequest(w, err.Error())
return
}

if isHTMXRequest(r) {
// For HTMX: Redirect to login page
w.Header().Set("HX-Redirect", "/login.html")
w.WriteHeader(http.StatusCreated)
} else {
// JSON API response
w.WriteHeader(http.StatusCreated)
}
w.WriteHeader(http.StatusCreated)
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
"author": "",
"license": "MIT",
"devDependencies": {
"@playwright/test": "^1.56.1"
"@playwright/test": "^1.48.0"
}
}
17 changes: 1 addition & 16 deletions public/js/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,7 @@ function setAuthToken(token) {
}

function getAuthToken() {
let token = localStorage.getItem('authToken');
if (!token) {
console.log('Auth token not found in localStorage, checking cookies');
// read from cookie as fallback
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].trim();
if (cookie.startsWith('authToken=')) {
token = cookie.substring('authToken='.length);
setAuthToken(token);
document.cookie = 'authToken=; path=/; max-age=0';
return token;
}
}
}
return token;
return localStorage.getItem('authToken');
}

function clearAuthToken() {
Expand Down
131 changes: 0 additions & 131 deletions public/js/htmx.min.js

This file was deleted.

Loading
Loading