package handlers import ( "errors" "net/http" "strings" "nestly/internal/models" ) // loginView 登入頁的模板資料。 type loginView struct { Email string Error string } // AuthHandler 處理登入與登出。 type AuthHandler struct { deps Dependencies } // Login 渲染登入頁;已登入者直接導向首頁。 func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { if _, err := h.deps.Sessions.UserID(r); err == nil { http.Redirect(w, r, "/", http.StatusSeeOther) return } if err := h.deps.Templates.Render(w, http.StatusOK, "login.html", loginView{}); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } // DoLogin 驗證 Email 與密碼,成功後建立 session 並導向首頁; // 失敗時重新渲染表單並保留使用者輸入的 Email。 func (h *AuthHandler) DoLogin(w http.ResponseWriter, r *http.Request) { email := strings.TrimSpace(r.PostFormValue("email")) password := r.PostFormValue("password") // 帳號不存在與密碼錯誤回應同一訊息,避免列舉有效 Email。 view := loginView{Email: email} acct, err := h.deps.Accounts.FindByEmail(r.Context(), email) if err != nil && !errors.Is(err, models.ErrNotFound) { http.Error(w, err.Error(), http.StatusInternalServerError) return } if err == nil && acct.VerifyPassword(password) { h.deps.Sessions.Login(w, acct.ID) http.Redirect(w, r, "/", http.StatusSeeOther) return } view.Error = "Email 或密碼不正確。" if err := h.deps.Templates.Render(w, http.StatusUnauthorized, "login.html", view); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } // Logout 清除 session 並回到登入頁。 func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) { h.deps.Sessions.Logout(w) http.Redirect(w, r, "/login", http.StatusSeeOther) }