This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-5311-6d604f340911153995c15bae5071723127b852e6 in repository https://gitbox.apache.org/repos/asf/texera.git
commit af664995e78e1cef5b9c727998cd335d98f0d92c Author: Matthew B. <[email protected]> AuthorDate: Wed Jun 3 16:04:55 2026 -0700 fix(frontend): stop forum login from looping when Flarum auth fails (#5311) ### What changes were proposed in this PR? - Add an `attemptRegister` flag to `DashboardComponent.forumLogin` so a Flarum registration is attempted at most once, breaking the infinite `auth -> register -> auth` cycle that occurred when `auth()` kept failing with a non-404/500 status. - After registering, the recursive call now passes `forumLogin(false)`; if auth still fails on that pass it falls through to `displayForum = false` instead of looping. - Add an error handler to the `register()` subscription so a failed registration hides the forum rather than being silently dropped. ### Any related issues, documentation, or discussions? Closes: #5310 ### How was this PR tested? - Ran `yarn format:fix` (clean, no files changed). - Manually traced the control flow: auth fail (non-404/500) now does auth, register, auth, then stop, instead of recursing without bound. ### Was this PR authored or co-authored using generative AI tooling? Co-authored with Claude Opus 4.8 in compliance with ASF --------- 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 aadf07d54b..8f8ba03b08 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), + }); } }, });
