This is an automated email from the ASF dual-hosted git repository.

xuang7 pushed a commit to branch release/v1.2
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/release/v1.2 by this push:
     new c9909b692d fix(frontend): stop forum login from looping when Flarum 
auth fails (#5311) [release/v1.2 backport] (#5615)
c9909b692d is described below

commit c9909b692d8926a4e8490a1b22d553d65d99318e
Author: Matthew B. <[email protected]>
AuthorDate: Wed Jun 10 22:12:45 2026 -0700

    fix(frontend): stop forum login from looping when Flarum auth fails (#5311) 
[release/v1.2 backport] (#5615)
    
    ### What changes were proposed in this PR?
    
    Backport of #5311 ("fix(frontend): stop forum login from looping when
    Flarum auth fails") to `release/v1.2`.
    
    Applies as a clean `git cherry-pick -x` of the merged squash commit
    `af664995`, no conflicts and no prerequisite chain. Frontend-only: 2
    files changed, 75 insertions, 4 deletions. The introduced diff is
    identical to the original PR (only blob-index hashes in the patch header
    differ).
    
    For the full change description see #5311. In brief:
    `DashboardComponent.forumLogin` recursed `auth -> register -> auth`
    without bound when Flarum `auth()` kept failing with a non-404/500
    status. This adds an `attemptRegister` flag so registration is attempted
    at most once (the post-register call passes `forumLogin(false)`, which
    then falls through to `displayForum = false`), and adds an error handler
    on the `register()` subscription so a failed registration hides the
    forum instead of being silently dropped.
    
    ### Any related issues, documentation, discussions?
    
    Closes: #5618 (backport tracking task). Backports #5311 (which closes
    #5310 on `main`). Requested by @xuang7 for the v1.2 release; the PR was
    merged before the `release/v1.2` label existed, so auto-backport did not
    trigger.
    
    ### How was this PR tested?
    
    This is a backport with no changes beyond the single cherry-picked
    commit, so it relies on the existing tests carried over from #5311
    (added cases in `dashboard.component.spec.ts` covering the bounded retry
    and the failed-registration path). Run them with `yarn test
    --include='**/dashboard.component.spec.ts'` from `frontend/`.
    
    Backport fidelity was verified locally: the diff introduced by the
    cherry-pick is byte-identical to the original #5311 diff. The
    `dashboard.component.ts` file is not byte-identical to `main@af664995`
    only because `release/v1.2` lacks the unrelated footer change
    (#5153/#5444) that renamed `gitCommitHash`/`Version.raw` to
    `buildNumber`/`Version.buildNumber`; that line is outside the
    `forumLogin` fix and is left untouched here.
    
    Full compile and unit-test runs are left to CI.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Claude Opus 4.8)
    
    Signed-off-by: Matthew B. <[email protected]>
---
 .../component/dashboard.component.spec.ts          | 67 +++++++++++++++++++++-
 .../app/dashboard/component/dashboard.component.ts | 12 +++-
 2 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/frontend/src/app/dashboard/component/dashboard.component.spec.ts 
b/frontend/src/app/dashboard/component/dashboard.component.spec.ts
index 29ed8426fe..a53244b3cd 100644
--- a/frontend/src/app/dashboard/component/dashboard.component.spec.ts
+++ b/frontend/src/app/dashboard/component/dashboard.component.spec.ts
@@ -21,7 +21,7 @@ import { ComponentFixture, TestBed } from 
"@angular/core/testing";
 import { DashboardComponent } from "./dashboard.component";
 import { ChangeDetectorRef, EventEmitter, NgZone } from "@angular/core";
 import { By } from "@angular/platform-browser";
-import { EMPTY, of } from "rxjs";
+import { EMPTY, of, throwError } from "rxjs";
 
 import { UserService } from "../../common/service/user/user.service";
 import { FlarumService } from "../service/user/flarum/flarum.service";
@@ -178,6 +178,71 @@ describe("DashboardComponent", () => {
     expect(fixture.debugElement.query(By.css("#powered-by"))).toBeTruthy();
   });
 
+  describe("forumLogin", () => {
+    const clearForumCookie = () =>
+      (document.cookie = "flarum_remember=; expires=Thu, 01 Jan 1970 00:00:00 
GMT; path=/");
+
+    beforeEach(() => {
+      clearForumCookie();
+      (userServiceMock.isLogin as Mock).mockReturnValue(true);
+      component.isLogin = true;
+      component.displayForum = true;
+      (flarumServiceMock.auth as Mock).mockClear();
+      (flarumServiceMock.register as Mock).mockClear();
+    });
+
+    afterEach(() => clearForumCookie());
+
+    it("stores the flarum_remember cookie on successful auth and does not 
register", () => {
+      (flarumServiceMock.auth as Mock).mockReturnValue(of({ token: "tok123" 
}));
+
+      component.forumLogin();
+
+      expect(document.cookie).toContain("flarum_remember=tok123");
+      expect(flarumServiceMock.register).not.toHaveBeenCalled();
+    });
+
+    it("hides the forum and does not register when auth fails with 404/500", 
() => {
+      (flarumServiceMock.auth as Mock).mockReturnValue(throwError(() => ({ 
status: 404 })));
+
+      component.forumLogin();
+
+      expect(component.displayForum).toBe(false);
+      expect(flarumServiceMock.register).not.toHaveBeenCalled();
+    });
+
+    it("registers at most once and stops when auth keeps failing (no infinite 
loop)", () => {
+      (flarumServiceMock.auth as Mock).mockReturnValue(throwError(() => ({ 
status: 401 })));
+      (flarumServiceMock.register as Mock).mockReturnValue(of(null));
+
+      component.forumLogin();
+
+      // auth -> register -> auth -> stop: register fires once, auth twice, 
then it terminates.
+      expect(flarumServiceMock.register).toHaveBeenCalledTimes(1);
+      expect(flarumServiceMock.auth).toHaveBeenCalledTimes(2);
+      expect(component.displayForum).toBe(false);
+    });
+
+    it("hides the forum when registration fails", () => {
+      (flarumServiceMock.auth as Mock).mockReturnValue(throwError(() => ({ 
status: 401 })));
+      (flarumServiceMock.register as Mock).mockReturnValue(throwError(() => ({ 
status: 500 })));
+
+      component.forumLogin();
+
+      expect(flarumServiceMock.register).toHaveBeenCalledTimes(1);
+      expect(component.displayForum).toBe(false);
+    });
+
+    it("does nothing when a flarum_remember cookie is already present", () => {
+      document.cookie = "flarum_remember=existing;path=/";
+
+      component.forumLogin();
+
+      expect(flarumServiceMock.auth).not.toHaveBeenCalled();
+      expect(flarumServiceMock.register).not.toHaveBeenCalled();
+    });
+  });
+
   it("should hide the navbar on workflow workspace routes", () => {
     expect(component.isNavbarEnabled("/user/workflow/42")).toBe(false);
     expect(component.isNavbarEnabled("/user/workflow")).toBe(true);
diff --git a/frontend/src/app/dashboard/component/dashboard.component.ts 
b/frontend/src/app/dashboard/component/dashboard.component.ts
index 8dc5d601dd..cec80766fc 100644
--- a/frontend/src/app/dashboard/component/dashboard.component.ts
+++ b/frontend/src/app/dashboard/component/dashboard.component.ts
@@ -204,7 +204,7 @@ export class DashboardComponent implements OnInit {
     });
   }
 
-  forumLogin() {
+  forumLogin(attemptRegister: boolean = true) {
     if (!document.cookie.includes("flarum_remember") && this.isLogin) {
       this.flarumService
         .auth()
@@ -214,13 +214,19 @@ export class DashboardComponent implements OnInit {
             document.cookie = `flarum_remember=${response.token};path=/`;
           },
           error: (err: unknown) => {
-            if ([404, 500].includes((err as HttpErrorResponse).status)) {
+            // Stop retrying on a missing/broken forum service, or once we have
+            // already attempted a registration, to avoid an infinite
+            // auth -> register -> auth loop when auth keeps failing.
+            if ([404, 500].includes((err as HttpErrorResponse).status) || 
!attemptRegister) {
               this.displayForum = false;
             } else {
               this.flarumService
                 .register()
                 .pipe(untilDestroyed(this))
-                .subscribe(() => this.forumLogin());
+                .subscribe({
+                  next: () => this.forumLogin(false),
+                  error: () => (this.displayForum = false),
+                });
             }
           },
         });

Reply via email to