Skip to content

feat: add endpoint to list disabled users with cursor-based pagination - #327

Open
francismars wants to merge 575 commits into
pubky:mainfrom
francismars:feat/admin-banned-users-api
Open

feat: add endpoint to list disabled users with cursor-based pagination#327
francismars wants to merge 575 commits into
pubky:mainfrom
francismars:feat/admin-banned-users-api

Conversation

@francismars

Copy link
Copy Markdown

Summary

This PR adds an admin endpoint in pubky-homeserver to list disabled users with cursor pagination.

  • Added GET /users/disabled to the admin protected router.
  • Added handler/query/response support for disabled users listing.
  • Added repository-level disabled-users pagination with deterministic ordering.

API contract

Endpoint

GET /users/disabled

Auth

Uses existing admin middleware (X-Admin-Password header).

Query params

  • limit?: u16
  • cursor?: string (z32 pubkey, non-inclusive)

Response

{
  "items": [{ "pubkey": "..." }],
  "next_cursor": "..." | null
}

Error behavior

  • Invalid cursor => 400 Bad Request (Invalid cursor)

Implementation details

  • Route wiring:
    • pubky-homeserver/src/admin_server/app.rs
  • Admin handler + response/query types:
    • pubky-homeserver/src/admin_server/routes/disable_users.rs
  • Persistence query + pagination:
    • pubky-homeserver/src/persistence/sql/entities/user.rs

Pagination behavior:

  • Filter on disabled = true
  • Deterministic order by public_key ascending
  • Cursor is non-inclusive (public_key > cursor)
  • Uses limit + 1 fetch to determine next_cursor

Test plan

  • cargo fmt
  • cargo check -p pubky-homeserver
  • Manual Umbrel validation:
    • Seeded users in Postgres (2 disabled, 1 enabled)
    • GET /users/disabled?limit=1 returned one disabled user + non-null next_cursor
    • Request with returned cursor returned remaining disabled user(s) + next_cursor: null
    • Invalid cursor returned 400
    • Enabled user was not returned

Nuhvi and others added 30 commits February 10, 2025 14:48
ok300 and others added 28 commits December 13, 2025 11:03
Testnet: Fix chosen timeout for client builder
* fix(sdk): null rust pointer error on authflow

* fix typo in docs

* add back regresion tests

* add docstring on reuse to structs
…y#294)

* feat(homeserver): add aditional admin info

* add admin server tests
Explicitly specify loopback IP when exposing container ports
…c ordering (pubky#295)

* fix: enforce C collation for entry listing order

* fix docs testing postgress connection string

* fix format
…ns (pubky#278)

* test: implement builder patternf or EphemeralTestnet

* test: disable admin server by default in tests

* fix: pr_check to poll http endpoint rather than admin

* feat:
	- Builder pattern for testnet's EphemeralTestnet. This allows for specifying config and keypair and is easily expandable.
	- Here we only implement the Builder pattern. Usage in pubky-core will follow.

* feat: add with_http_relay()
* feat: add pubky keys type

* fix clippy

* fixes

* fix e2e

* fix wasm tests

* add secret export method to keypair wrapper

* fmt

* fix clippy

* tigten prefix handling

* tighten wasm public key conversion

* ensure no double  encoding

* fix docs and enfore non-prefixed keys on transport

* fix docs, remove collate C

* more strict where z32 only is expected with useful messages

* centralized is_prefixed_pubky check on pubky-common

* use z32 on query params

* fix wasm clippy

* fix e2e

* fix admin tests for pubky keys

* aling expected e2e order/cursor to collate C expectations

* revert e2e storage utils

* tackle review comments

* small refactor

* rename .seed() to .secret()

* use testnet builder on e2e tests
* feat: events-stream sdk support

* chore: styling

* fix:
	- Add_user max users check bug fix
	- Use u64 for event.id and pass in from JS as String
	- Parse SSE Events by prefix rather than assuming line position

* fix: A couple of nits from PR review

* feat: User PubkyResource in SDK and use in Event

* fix: Import change after main merge
…g-group-prs

chore: Group `dependabot` PRs
…#304)

Dependabot

The package name 'examples' conflicts with Cargo's reserved build
directory names, causing Dependabot to fail with "the binary target
name `examples` is forbidden, it conflicts with cargo's build
directory names".

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* feat: Add feature for embedded postgres

* feat: require postgres() xor with_embedded_postgres()

* test: reduce to single test for speed
* Consolidate, bump log to 0.4.29

* Bump serde_json to 1.0.149

* Consolidate, bump url to 2.5.8

* Consolidate, bump anyhow to 1.0.101

* Consolidate, bump axum to 0.8.8

* Consolidate, bump tracing to 0.1.44

* Consolidate, bump tower-http to 0.6.8

* Consolidate, bump thiserror to 2.0.18

* Consolidate, bump clap to 4.5.58

* Consolidate, bump tracing-subscriber to 0.3.22

* Bump ctrlc to 3.5.2
* Bump pkarr, pkarr-relay, axum-server

* Fix ClientBuilder type mismatch by upgrading reqwest to 0.13 (pubky#45)

pkarr 5.0.3 implements `From<pkarr::Client> for reqwest::ClientBuilder`
against reqwest 0.13, but pubky-sdk and pubky-wasm depended on reqwest
0.12. This version mismatch caused the compiler to not find the From
impl, falling back to the blanket `From<T> for T` which expected a
ClientBuilder argument instead of a pkarr::Client.

Update reqwest from 0.12 to 0.13 in both pubky-sdk (with rustls-tls
renamed to rustls) and pubky-wasm to match pkarr's reqwest version.

https://claude.ai/code/session_01THELgcvbReeW9EPBsiV5vd

Co-authored-by: Claude <noreply@anthropic.com>

* Cargo fmt

* Fix CI tests after dependency updates (pkarr 5.0.3, axum-server 0.8.0) (pubky#47)

* Initial plan

* Fix CI test failures: tokio blocking socket and pkarr testnet node count

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* Fix wasm-test CI failure by upgrading wasm-streams to 0.5 (pubky#48)

* Initial plan

* Fix wasm-test CI failure by upgrading wasm-streams to 0.5

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* Add RUSTFLAGS for tokio blocking fd support in CI test job (pubky#49)

* Initial plan

* Add RUSTFLAGS to test job to fix CI failures with axum-server 0.8.0

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* Fix axum-server 0.8.0 API compatibility in rate limiter tests (pubky#50)

* Initial plan

* Fix axum-server API change: replace Server::from_tcp with Server::from_listener

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* Bump mainline

* Fix slow CI tests by wrapping mainline DHT creation in spawn_blocking (pubky#53)

* Initial plan

* Wrap mainline DHT creation in spawn_blocking to prevent blocking tokio runtime

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* Cargo fmt

* Add tokio_allow_from_blocking_fd flag to wasm-test

* pubky-testnet: remove superfluous tokio spawning

* Remove remaining un-necessary tokio spawning

* fix: set TcpListeners to non-blocking before passing to axum-server (pubky#56)

* Initial plan

* Investigation: test_signup hangs due to blocking TcpListener

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* fix: set TcpListener to non-blocking mode before passing to axum-server

All std::net::TcpListener instances passed to axum_server::from_tcp()
must be set to non-blocking mode. Tokio 1.49+ panics (debug_assert) when
registering blocking file descriptors with the runtime. This caused
test_signup and other tests to either panic or hang indefinitely.

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* ci: remove tokio_allow_from_blocking_fd RUSTFLAGS workaround

No longer needed since all TcpListeners are now set to non-blocking
mode before being passed to axum-server.

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* fix: declare `imports` variable in patch.mjs for wasm-bindgen 0.2.108+ (pubky#57)

* fix: declare 'imports' variable in patch.mjs for newer wasm-bindgen output

wasm-bindgen 0.2.108 no longer generates 'module.exports' patterns.
The patch script relied on replacing '= module.exports' to implicitly
declare the 'imports' variable. When this pattern is absent, we now
explicitly declare 'const imports = {}' at the top of the output.

Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* Bump wasm-bindgen

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com>

* Consolidate, bump tokio

* Consolidate, bump reqwest

* Revert off-by-one test changes

* Switch publisher, republisher tests to Testnet::new_unseeded

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
…factor (pubky#318)

* increased auth token life time from 45s to 3min + clean code refactor

* fmt
* feat: GET /signup entrypoint for signup_token validation

* feat: create new signup_tokens resource endpoint instead of hacking /signup
…p_tokens` route (pubky#323)

* feat: set 10 request per ip per minute default rate limit for /signup_tokens route

* test: add test for signup_token rate limit. Also use testnet builder throughout e2e tests file
* Implemented `GET /users/disabled` route to retrieve disabled users.
* Added pagination support using cursor for efficient data retrieval.
* Updated `UserRepository` to include a method for fetching disabled users.
* Added tests for the new endpoint and pagination functionality.
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.