diff --git a/server/api/auth.go b/server/api/auth.go deleted file mode 100644 index 0035e46..0000000 --- a/server/api/auth.go +++ /dev/null @@ -1,126 +0,0 @@ -package api - -import ( - "bytes" - "encoding/json" - "log/slog" - "net/http" - "net/url" - "os" - "strings" - "time" - - "github.com/gin-gonic/gin" -) - -const defaultAccountServiceURL = "http://localhost:8080" - -var accountServiceHTTPClient = &http.Client{Timeout: 10 * time.Second} - -func registerAuthRoutes(r *gin.RouterGroup) { - r.POST("/auth/register", handleAuthRegister) -} - -func handleAuthRegister(c *gin.Context) { - name := strings.TrimSpace(c.PostForm("name")) - email := strings.ToLower(strings.TrimSpace(c.PostForm("email"))) - password := c.PostForm("password") - confirm := c.PostForm("confirmPassword") - - if email == "" || password == "" { - redirectWithError(c, "missing_fields") - return - } - - if password != confirm { - redirectWithError(c, "password_mismatch") - return - } - - payload := map[string]string{ - "name": name, - "email": email, - "password": password, - } - - body, err := json.Marshal(payload) - if err != nil { - slog.Error("marshal register payload", "err", err) - redirectWithError(c, "registration_failed") - return - } - - req, err := http.NewRequestWithContext( - c.Request.Context(), - http.MethodPost, - accountServiceRegisterURL(), - bytes.NewReader(body), - ) - if err != nil { - slog.Error("create account service request", "err", err) - redirectWithError(c, "registration_failed") - return - } - req.Header.Set("Content-Type", "application/json") - - resp, err := accountServiceHTTPClient.Do(req) - if err != nil { - slog.Error("call account service", "err", err) - redirectWithError(c, "registration_failed") - return - } - defer resp.Body.Close() - - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - var result struct { - Error string `json:"error"` - } - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - slog.Error("decode account service error", "err", err) - } - message := strings.TrimSpace(result.Error) - if message == "" { - message = "registration_failed" - } - redirectWithError(c, message) - return - } - - redirectToLogin(c) -} - -func redirectWithError(c *gin.Context, message string) { - target := &url.URL{Path: "/register"} - values := url.Values{} - values.Set("error", message) - target.RawQuery = values.Encode() - c.Redirect(http.StatusSeeOther, target.String()) -} - -func redirectToLogin(c *gin.Context) { - target := &url.URL{Path: "/login"} - values := url.Values{} - values.Set("registered", "1") - target.RawQuery = values.Encode() - c.Redirect(http.StatusSeeOther, target.String()) -} - -func accountServiceRegisterURL() string { - base := strings.TrimSuffix(resolveAccountServiceBaseURL(), "/") - return base + "/v1/register" -} - -func resolveAccountServiceBaseURL() string { - candidates := []string{ - os.Getenv("ACCOUNT_SERVICE_URL"), - os.Getenv("ACCOUNT_SERVICE_BASE_URL"), - os.Getenv("NEXT_PUBLIC_ACCOUNT_SERVICE_URL"), - } - for _, candidate := range candidates { - candidate = strings.TrimSpace(candidate) - if candidate != "" { - return candidate - } - } - return defaultAccountServiceURL -} diff --git a/server/api/auth_test.go b/server/api/auth_test.go deleted file mode 100644 index 07c7840..0000000 --- a/server/api/auth_test.go +++ /dev/null @@ -1,147 +0,0 @@ -package api - -import ( - "encoding/json" - "net/http" - "net/http/httptest" - "net/url" - "strings" - "testing" - - "github.com/gin-gonic/gin" -) - -func TestHandleAuthRegisterSuccess(t *testing.T) { - gin.SetMode(gin.TestMode) - - account := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - t.Fatalf("expected POST, got %s", r.Method) - } - if r.URL.Path != "/v1/register" { - t.Fatalf("unexpected path: %s", r.URL.Path) - } - var payload map[string]string - if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { - t.Fatalf("decode payload: %v", err) - } - if payload["email"] != "user@example.com" { - t.Fatalf("unexpected email: %s", payload["email"]) - } - w.WriteHeader(http.StatusCreated) - })) - defer account.Close() - - prevClient := accountServiceHTTPClient - accountServiceHTTPClient = account.Client() - t.Cleanup(func() { accountServiceHTTPClient = prevClient }) - - t.Setenv("ACCOUNT_SERVICE_URL", account.URL) - - router := gin.New() - registerAuthRoutes(router.Group("/api")) - - form := url.Values{} - form.Set("name", "Example User") - form.Set("email", "user@example.com") - form.Set("password", "YOUR_PASSWORD") - form.Set("confirmPassword", "YOUR_PASSWORD") - - req := httptest.NewRequest(http.MethodPost, "/api/auth/register", strings.NewReader(form.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - res := httptest.NewRecorder() - - router.ServeHTTP(res, req) - - if res.Code != http.StatusSeeOther { - t.Fatalf("expected status %d, got %d", http.StatusSeeOther, res.Code) - } - if location := res.Header().Get("Location"); location != "/login?registered=1" { - t.Fatalf("unexpected location: %s", location) - } -} - -func TestHandleAuthRegisterMissingFields(t *testing.T) { - gin.SetMode(gin.TestMode) - router := gin.New() - registerAuthRoutes(router.Group("/api")) - - form := url.Values{} - form.Set("email", "") - form.Set("password", "secret123") - form.Set("confirmPassword", "secret123") - - req := httptest.NewRequest(http.MethodPost, "/api/auth/register", strings.NewReader(form.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - res := httptest.NewRecorder() - - router.ServeHTTP(res, req) - - if res.Code != http.StatusSeeOther { - t.Fatalf("expected status %d, got %d", http.StatusSeeOther, res.Code) - } - if location := res.Header().Get("Location"); location != "/register?error=missing_fields" { - t.Fatalf("unexpected location: %s", location) - } -} - -func TestHandleAuthRegisterPasswordMismatch(t *testing.T) { - gin.SetMode(gin.TestMode) - router := gin.New() - registerAuthRoutes(router.Group("/api")) - - form := url.Values{} - form.Set("email", "user@example.com") - form.Set("password", "secret123") - form.Set("confirmPassword", "secret321") - - req := httptest.NewRequest(http.MethodPost, "/api/auth/register", strings.NewReader(form.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - res := httptest.NewRecorder() - - router.ServeHTTP(res, req) - - if res.Code != http.StatusSeeOther { - t.Fatalf("expected status %d, got %d", http.StatusSeeOther, res.Code) - } - if location := res.Header().Get("Location"); location != "/register?error=password_mismatch" { - t.Fatalf("unexpected location: %s", location) - } -} - -func TestHandleAuthRegisterServiceError(t *testing.T) { - gin.SetMode(gin.TestMode) - - account := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusConflict) - _ = json.NewEncoder(w).Encode(map[string]string{"error": "user already exists"}) - })) - defer account.Close() - - prevClient := accountServiceHTTPClient - accountServiceHTTPClient = account.Client() - t.Cleanup(func() { accountServiceHTTPClient = prevClient }) - - t.Setenv("ACCOUNT_SERVICE_URL", account.URL) - - router := gin.New() - registerAuthRoutes(router.Group("/api")) - - form := url.Values{} - form.Set("email", "user@example.com") - form.Set("password", "secret123") - form.Set("confirmPassword", "secret123") - - req := httptest.NewRequest(http.MethodPost, "/api/auth/register", strings.NewReader(form.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - res := httptest.NewRecorder() - - router.ServeHTTP(res, req) - - if res.Code != http.StatusSeeOther { - t.Fatalf("expected status %d, got %d", http.StatusSeeOther, res.Code) - } - if location := res.Header().Get("Location"); location != "/register?error=user+already+exists" { - t.Fatalf("unexpected location: %s", location) - } -} diff --git a/server/api/register.go b/server/api/register.go index 5d17492..0845d85 100644 --- a/server/api/register.go +++ b/server/api/register.go @@ -11,7 +11,6 @@ import ( func RegisterRoutes(conn *pgx.Conn, repoProxy string) server.Registrar { return func(r *gin.Engine) { api := r.Group("/api") - registerAuthRoutes(api) registerUserRoutes(api) registerNodeRoutes(api) registerKnowledgeRoutes(api, conn, repoProxy)