Skip to content

[2.x] fix: include user groups when listing discussions - #4928

Merged
imorland merged 1 commit into
2.xfrom
im/discussion-list-user-groups
Aug 12, 2026
Merged

[2.x] fix: include user groups when listing discussions#4928
imorland merged 1 commit into
2.xfrom
im/discussion-list-user-groups

Conversation

@imorland

Copy link
Copy Markdown
Member

Fixes #0000

Changes proposed in this pull request:

Click a user's avatar in the discussion list and their profile opens with no badges. Reload the page and the badges appear.

DiscussionResource's Index endpoint eager-loads user.groups but never lists it in defaultInclude. eagerLoad is a database optimisation — it populates the Eloquent relation so the permission checks (isAdmin(), canEdit, and friends) don't fire a query per user. It does not put anything in the JSON:API document. So the groups were loaded, used for permissions, then discarded before serialisation, and every user in the list came back with no groups relationship at all.

That alone means no badges. But it also outlives the request: the frontend keeps that group-less user in its store, and UserPage::loadUser() scans the store first — finding a user with a joinTime(), it calls show() and returns without fetching. So UserResource's Show endpoint, which does have defaultInclude(['groups']), never runs. A hard reload empties the store, the fetch happens, and the badges come back — which is why it looks like a caching problem rather than a payload one.

Show had the same gap. It already included firstPost.user.groups, so the post author serialised correctly while the discussion author and last poster didn't, despite all three being eager-loaded. #4695 fixed the eager-loading for all three but only added the include for one; this finishes it.

Every include added here already had a matching eagerLoad on the same endpoint.

Reviewers should focus on:

  • That this genuinely adds no queries. That's the whole basis of the change, so I measured it rather than assuming. Over ten discussions with twenty distinct users, group_user is queried 3 times before and 3 times after. The new test asserts this, and I checked it isn't vacuous: removing the eagerLoad while keeping the includes makes it fail.
  • Payload size, since this is the busiest endpoint in the app. Measured on a real forum: +2,534 bytes on a 20-discussion page, +2.7%, uncompressed. Group names repeat heavily across users and JSON:API dedupes the groups resources themselves (23 users → 5 group resources), so gzip takes most of that back. Still, it is a payload increase on the discussion list and worth a deliberate yes rather than being waved through.
  • Hidden groups. Including groups must not become a way to see groups you otherwise couldn't. Filtering already happens in UserResource's groups relationship getter, which checks viewHiddenGroups — there's a test pinning it, but worth a second pair of eyes given this widens where groups are serialised.

Screenshot

No visual change to the discussion list itself. The difference is on the profile you land on after clicking an avatar: badges present immediately instead of after a reload.

Necessity

  • Has the problem that is being solved here been clearly explained?
  • If applicable, have various options for solving this problem been considered?
  • For core PRs, does this need to be in core, or could it be in an extension?
  • Are we willing to maintain this for years / potentially forever?

Confirmed

  • Frontend changes: tested on a local Flarum installation.
  • Frontend changes: tests are green (run yarn test in js/). — no frontend changes
  • Frontend changes: tests have been added, or are not appropriate here. — no frontend changes
  • Backend changes: tests are green (run composer test).
  • Backend changes: tests have been added, or are not appropriate here.
  • Where applicable, changes are suitable for all supported database drivers (MySQL, MariaDB, PostgreSQL, SQLite).
  • Core developer confirmed locally this works as intended.
  • The description above is written by me and describes what this pull request actually does.

New ListGroupsQueryCountTest, modelled on the existing ShowGroupsQueryCountTest from #4695: ten discussions with twenty distinct users, so a per-user query shows up as a multiple of the page size rather than hiding in a constant. Covers query count, groups actually being present, and hidden groups staying hidden. 57 discussion API tests green, including the pre-existing query-count tests. PHPStan clean.

Required changes:

  • Related documentation PR: (Remove if irrelevant)

The discussion list eager-loaded `user.groups` but never listed it in
`defaultInclude`, so the groups were loaded for the permission checks and
then discarded before serialisation. Every user in the list arrived with
no groups at all.

That is enough on its own — a user with no groups has no badges — but it
also outlives the request. The frontend keeps the group-less record in
its store, and opening that user's profile finds it there and skips
fetching the user again, so the profile stays badge-less until the page
is reloaded.

`Show` had the same gap. It already included `firstPost.user.groups`, so
the post author was fine while the discussion author and last poster were
not; all three were eager-loaded.

No new queries: the relations were already loaded for these very users,
and this only serialises what was being thrown away. Measured over a page
of ten discussions with twenty distinct users, `group_user` is queried
three times before and after.
@imorland
imorland requested a review from a team as a code owner August 12, 2026 16:03
@imorland imorland changed the title fix: include user groups when listing discussions [2.x] fix: include user groups when listing discussions Aug 12, 2026
@imorland imorland added this to the 2.0.0-rc.6 milestone Aug 12, 2026
@imorland
imorland merged commit 1de1e84 into 2.x Aug 12, 2026
25 checks passed
@imorland
imorland deleted the im/discussion-list-user-groups branch August 12, 2026 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant