Page through every channel membership #401

Merged
robbertbos merged 2 commits from postvak-paginate-channel-memberships into main 2026-09-20 21:59:03 +00:00
Owner

The Postvak came up empty on a production account while Mattermost showed an unread channel. GET /users/me/channel_members pages at 60 without an explicit per_page, and the client read one page. A channel whose membership never arrives is skipped in mm_unread.py (if member is None: continue), so the rows quietly disappear and the endpoint answers {"items":[]} with a 200.

Measured on that account: 458 memberships, 60 fetched, and the only non-muted unread channel sat outside them.

The walk asks for 200 per page and stops on a short page. It also stops on a page that adds no new ids, because /users/me/channels ignores paging and serves the full list for every page - a short-page check alone never terminates against that. A 50-page cap bounds it either way.

Tests

Three, all in test_mattermost_unread_client.py: the walk collects 250 rows across pages (fails before this change with first extra item: 'c60'), it terminates against an endpoint that ignores paging, and it stops at the cap. The existing URL assertion moves to the paged URL.

Found while debugging, not in this PR

  • resolve_crt_enabled reads the collapsed-reply-threads preference from /preferences/display/collapsed_reply_threads. Mattermost serves it at /preferences/display_settings/name/collapsed_reply_threads: wrong category, and the /name/ segment is missing. The 404 that comes back is read as "not set", which under CollapsedThreads: default_on resolves to on - which happens to be the right answer today, so nothing shows. Turn CRT off and the Postvak empties again.
  • That route answers 400, not 404, for a preference that does not exist. get_user_preference only translates 404, so fixing the URL alone turns the silent default into a 502.
  • Two open questions filed as #400: 38 memberships without a channel row, and muted channels with unread messages surfacing in neither the Postvak nor Meelezen.
The Postvak came up empty on a production account while Mattermost showed an unread channel. `GET /users/me/channel_members` pages at 60 without an explicit `per_page`, and the client read one page. A channel whose membership never arrives is skipped in `mm_unread.py` (`if member is None: continue`), so the rows quietly disappear and the endpoint answers `{"items":[]}` with a 200. Measured on that account: 458 memberships, 60 fetched, and the only non-muted unread channel sat outside them. The walk asks for 200 per page and stops on a short page. It also stops on a page that adds no new ids, because `/users/me/channels` ignores paging and serves the full list for every page - a short-page check alone never terminates against that. A 50-page cap bounds it either way. ### Tests Three, all in `test_mattermost_unread_client.py`: the walk collects 250 rows across pages (fails before this change with `first extra item: 'c60'`), it terminates against an endpoint that ignores paging, and it stops at the cap. The existing URL assertion moves to the paged URL. ### Found while debugging, not in this PR - `resolve_crt_enabled` reads the collapsed-reply-threads preference from `/preferences/display/collapsed_reply_threads`. Mattermost serves it at `/preferences/display_settings/name/collapsed_reply_threads`: wrong category, and the `/name/` segment is missing. The 404 that comes back is read as "not set", which under `CollapsedThreads: default_on` resolves to on - which happens to be the right answer today, so nothing shows. Turn CRT off and the Postvak empties again. - That route answers 400, not 404, for a preference that does not exist. `get_user_preference` only translates 404, so fixing the URL alone turns the silent default into a 502. - Two open questions filed as #400: 38 memberships without a channel row, and muted channels with unread messages surfacing in neither the Postvak nor Meelezen.
Page through every channel membership
Some checks failed
CI / release-scripts (pull_request) Successful in 9s
security-scan / SBOM (trivy) (pull_request) Successful in 10s
security-scan / JS SCA (npm audit) (pull_request) Successful in 14s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 15s
security-scan / Python SAST (bandit) (pull_request) Successful in 20s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 37s
test-build / build (frontend) (pull_request) Successful in 55s
CI / pre-commit (pull_request) Successful in 57s
test-build / build (backend) (pull_request) Successful in 59s
CI / frontend-test (pull_request) Successful in 1m0s
test-build / build (pull_request) Successful in 0s
CI / backend-test (pull_request) Successful in 2m37s
CI / e2e (pull_request) Has been cancelled
1010a022e2
Mattermost serves /users/me/channel_members 60 rows at a time. The client
read one page, so a user in more channels lost the rest: the Postvak
skipped every channel whose membership never arrived, down to an empty
list while Mattermost showed unread messages.

Measured on production: 458 memberships, 60 fetched, and the one unread
channel sat outside them.

The walk also stops on a page that adds no new ids. The sibling endpoint
/users/me/channels ignores paging and serves the full list for every
page; a short-page check alone would loop forever against that.
Drop the Dutch word from the changelog heading
Some checks failed
CI / release-scripts (pull_request) Successful in 9s
security-scan / SBOM (trivy) (pull_request) Successful in 11s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 17s
security-scan / JS SCA (npm audit) (pull_request) Successful in 18s
security-scan / Python SAST (bandit) (pull_request) Successful in 20s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 40s
test-build / build (frontend) (pull_request) Successful in 58s
CI / pre-commit (pull_request) Successful in 1m1s
CI / frontend-test (pull_request) Successful in 1m2s
test-build / build (backend) (pull_request) Successful in 1m4s
test-build / build (pull_request) Successful in 0s
CI / backend-test (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
6daa27a000
robbertbos force-pushed postvak-paginate-channel-memberships from 6daa27a000
Some checks failed
CI / release-scripts (pull_request) Successful in 9s
security-scan / SBOM (trivy) (pull_request) Successful in 11s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 17s
security-scan / JS SCA (npm audit) (pull_request) Successful in 18s
security-scan / Python SAST (bandit) (pull_request) Successful in 20s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 40s
test-build / build (frontend) (pull_request) Successful in 58s
CI / pre-commit (pull_request) Successful in 1m1s
CI / frontend-test (pull_request) Successful in 1m2s
test-build / build (backend) (pull_request) Successful in 1m4s
test-build / build (pull_request) Successful in 0s
CI / backend-test (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
to 3585b0220c
Some checks failed
CI / release-scripts (pull_request) Successful in 13s
security-scan / SBOM (trivy) (pull_request) Successful in 13s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 18s
security-scan / JS SCA (npm audit) (pull_request) Successful in 20s
security-scan / Python SAST (bandit) (pull_request) Successful in 22s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 42s
test-build / build (frontend) (pull_request) Successful in 1m0s
CI / pre-commit (pull_request) Successful in 1m0s
CI / frontend-test (pull_request) Successful in 1m2s
test-build / build (backend) (pull_request) Successful in 1m4s
test-build / build (pull_request) Successful in 0s
CI / backend-test (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
2026-09-20 21:52:49 +00:00
Compare
Shorten the scale-to-zero changelog entry
Some checks failed
CI / release-scripts (pull_request) Successful in 13s
security-scan / SBOM (trivy) (pull_request) Successful in 14s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 19s
security-scan / JS SCA (npm audit) (pull_request) Successful in 19s
security-scan / Python SAST (bandit) (pull_request) Successful in 24s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 42s
test-build / build (frontend) (pull_request) Successful in 1m0s
CI / pre-commit (pull_request) Successful in 1m1s
CI / frontend-test (pull_request) Successful in 1m3s
test-build / build (backend) (pull_request) Successful in 1m6s
test-build / build (pull_request) Successful in 0s
CI / backend-test (pull_request) Successful in 2m52s
CI / e2e (pull_request) Successful in 4m52s
CI / release-scripts (push) Successful in 8s
security-scan / SBOM (trivy) (push) Successful in 10s
security-scan / Filesystem scan (trivy fs) (push) Successful in 16s
security-scan / JS SCA (npm audit) (push) Successful in 16s
security-scan / Python SAST (bandit) (push) Successful in 20s
security-scan / Python SCA (pip-audit) (push) Successful in 38s
CI / pre-commit (push) Successful in 58s
CI / frontend-test (push) Successful in 1m0s
publish-and-stage / build (frontend) (push) Successful in 1m12s
publish-and-stage / build (backend) (push) Successful in 1m20s
publish-and-stage / build (push) Successful in 0s
CI / backend-test (push) Successful in 2m42s
publish-and-stage / deploy-staging (push) Has been cancelled
CI / e2e (push) Has been cancelled
a8b164c9d5
robbertbos deleted branch postvak-paginate-channel-memberships 2026-09-20 21:59:03 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
robbertbos/waggle!401
No description provided.