Skip to content

Address code-review findings (#1 hardening, #2, #6, #7, #8)#4

Merged
karl-bullock merged 3 commits into
mainfrom
review-fixes-v1.4.0
Jul 14, 2026
Merged

Address code-review findings (#1 hardening, #2, #6, #7, #8)#4
karl-bullock merged 3 commits into
mainfrom
review-fixes-v1.4.0

Conversation

@karl-bullock

Copy link
Copy Markdown
Member

Addresses the actionable items from the v1.4.0 code review (#3).

Changes

  • Code review (Floxum): chunk backfill migration, pagination caps, GET-path write, length guards, admin/TS cleanups #2 (production risk): cap the referredUsers include. ?include=referredUsers did an unbounded ->get(); it is now ordered newest-first and capped at 100 with a documented constant, so a prolific referrer can't trigger a huge read/payload.
  • #7 (production risk): guard generateUniqueCode(). The collision retry loop is now bounded to 10 attempts and throws a RuntimeException on exhaustion instead of potentially looping forever.
  • #8 (conventions): constructor-inject NotificationSyncer. Resolved via the constructor instead of Container::make(); the container is kept only for the genuinely request-scoped PendingReferralState.
  • #6 (dead code): remove unused Avatar / humanTime registry lookups from forum.js; dist rebuilt.
  • Floxum code review: Approved (v1.2.1) #1 (hardening): make the NotificationList.content override resilient. The full override now runs inside a try/catch that falls back to core's original content() on any error, so a future core refactor degrades to plain notification rendering instead of breaking the whole notifications page. The comment is pinned to the core version it mirrors, and a regression test locks the serialized contract the override reads.

The other review findings (#3 column-on-users, #4 source layout) were assessed as not valid and are not changed; see the triage notes in #3.

Verification

  • PHPStan level 6: clean
  • Unit tests: 6/6; integration tests: 17/17 (including the new notification-grouping contract test)
  • Frontend build + prettier: clean

Note: while writing the #1 regression test I found a separate, more serious upstream issue where this extension's User-subject notification can make core's /api/notifications return a 400 on forums without a Post-subject notification type. That is reported and fixed upstream (flarum/framework#4815, flarum/framework#4816) and is out of scope for this PR.

- Cap the referredUsers include at 100 rows, newest-first, so
  ?include=referredUsers can't do an unbounded read on a prolific
  referrer (#2).
- Add a 10-attempt guard to InviteCode::generateUniqueCode() that
  throws instead of looping forever if the code space is exhausted (#7).
- Constructor-inject NotificationSyncer into RecordReferral; keep the
  container only for the request-scoped PendingReferralState (#8).
- Drop the unused Avatar and humanTime registry lookups from forum.js
  and rebuild dist (#6).
The forum-side grouping fully overrides core's NotificationList.content,
which couples it to core internals. Add three guards:

- Pin the comment to the core version the copy mirrors (2.0.0-rc.5) with
  a note to reconcile on core bumps.
- Wrap the reproduced pipeline in try/catch that falls back to core's
  original content() on any error, so a future core refactor degrades to
  plain notification rendering instead of breaking the whole list. Also
  filter null NotificationType vnodes to match core.
- Add an integration test locking the serialized contract the override
  reads: contentType == linkrobinsReferralRegistered and a users subject.

Rebuild dist.
The referredUsers ToMany getter returned an Illuminate Collection, which
core's ToMany::serializeValue array_maps over after it has been coerced to
an array, turning each User model into its array form and throwing
"resource(): Argument #1 ($model) must be of type object, array given"
(HTTP 500) on any ?include=referredUsers request. This affected the
relationship regardless of the row cap.

Return a plain array of User objects (->all()) so each item stays an object
through serialization.

Adds integration coverage for the include (owner sees the referred user;
non-owner does not), which the relationship never had.
@karl-bullock

Copy link
Copy Markdown
Member Author

Update from an end-to-end test in a live sandbox forum: the referredUsers relationship was actually broken (HTTP 500) on any ?include=referredUsers request, on both main and this branch. Review finding #2 assumed the query merely lacked a cap, but it never serialized at all: the getter returned an Illuminate Collection, which core's ToMany::serializeValue coerces to an array (turning each User model into its array form) and then rejects with resource(): Argument #1 ($model) must be of type object, array given.

Pushed 270409f: return a plain array of User objects (->all()) so serialization works, plus integration coverage the relationship never had (owner sees the referred user; non-owner does not). The row cap from the earlier commit still applies.

The rest of the referral flow was verified working end-to-end in the sandbox: code generation, registration with an invite code, referral recorded + counter incremented + code uses incremented, referrer notified, and the notifications endpoint returning 200 with the correctly-serialized referral notification.

@karl-bullock karl-bullock merged commit d4a29a3 into main Jul 14, 2026
18 checks passed
@karl-bullock karl-bullock deleted the review-fixes-v1.4.0 branch July 14, 2026 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant