From 3daef344c154cf745ea759a9947e5f70f3bdc325 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 15 Jun 2026 18:28:55 -0700 Subject: [PATCH 1/3] fix: simplify ping handler to use user_id query param instead of wallet auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The handler was using getAuthedWallet(c) which required signature-based auth, then updating by wallet address. This was overcomplicated for a fire-and-forget activity signal. Now uses myId from the user_id query param (already decoded by resolveMyIdMiddleware) and updates by user_id. Removes requireAuthMiddleware from the route since the handler no longer needs the wallet — the global authMiddleware still validates signatures. Co-Authored-By: Claude Opus 4.6 --- api/resolve_middleware.go | 1 - api/server.go | 2 +- api/v1_users_ping.go | 9 ++++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/api/resolve_middleware.go b/api/resolve_middleware.go index a19809f0..51ca1d88 100644 --- a/api/resolve_middleware.go +++ b/api/resolve_middleware.go @@ -45,7 +45,6 @@ func (app *ApiServer) getUserId(c *fiber.Ctx) int32 { } func (app *ApiServer) requireUserIdMiddleware(c *fiber.Ctx) error { - // Allow /users/me/* routes to pass through without userId resolution if c.Params("userId") == "me" { return c.Next() } diff --git a/api/server.go b/api/server.go index 8674f83d..49bd7315 100644 --- a/api/server.go +++ b/api/server.go @@ -406,7 +406,7 @@ func NewApiServer(config config.Config) *ApiServer { g.Get("/users/genre/top", app.v1UsersGenreTop) g.Get("/users/account/:wallet", app.requireAuthMiddleware, app.v1UsersAccount) g.Get("/users/verify_token", app.v1UsersVerifyToken) - g.Post("/users/me/ping", app.requireAuthMiddleware, app.postV1UsersPing) + g.Post("/users/me/ping", app.postV1UsersPing) g.Use("/users/handle/:handle", app.requireHandleMiddleware) g.Get("/users/handle/:handle", app.v1User) diff --git a/api/v1_users_ping.go b/api/v1_users_ping.go index c222b726..4c2f7a71 100644 --- a/api/v1_users_ping.go +++ b/api/v1_users_ping.go @@ -10,14 +10,17 @@ func (app *ApiServer) postV1UsersPing(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusServiceUnavailable, "writes not available") } - wallet := app.getAuthedWallet(c) + myId := app.getMyId(c) + if myId == 0 { + return fiber.NewError(fiber.StatusBadRequest, "user_id query param is required") + } _, err := app.writePool.Exec(c.Context(), ` UPDATE users SET last_active_at = now() - WHERE wallet = $1 + WHERE user_id = $1 AND is_current = true - `, wallet) + `, myId) if err != nil { app.logger.Error("postV1UsersPing: failed to update last_active_at", zap.Error(err)) return fiber.NewError(fiber.StatusInternalServerError, "failed to record activity") From 82b12b00cc9f665032ea5f1cea1ca55450eebc72 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 15 Jun 2026 18:40:31 -0700 Subject: [PATCH 2/3] test: add integration tests for POST /v1/users/me/ping Covers the three key paths: - Authenticated request with valid user_id returns 200 - Missing user_id returns 400 - Unauthenticated request with user_id returns 403 Co-Authored-By: Claude Opus 4.6 --- api/v1_users_ping_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 api/v1_users_ping_test.go diff --git a/api/v1_users_ping_test.go b/api/v1_users_ping_test.go new file mode 100644 index 00000000..33b978c5 --- /dev/null +++ b/api/v1_users_ping_test.go @@ -0,0 +1,32 @@ +package api + +import ( + "testing" + + "api.audius.co/database" + "api.audius.co/api/testdata" + "github.com/stretchr/testify/assert" +) + +func TestPostV1UsersPing(t *testing.T) { + app := emptyTestApp(t) + database.SeedTable(app.pool.Replicas[0], "users", testdata.UserFixtures) + + // user 1 = wallet 0x7d273271690538cf855e5b3002a0dd8c154bb060, encoded = 7eP5n + wallet := "0x7d273271690538cf855e5b3002a0dd8c154bb060" + + t.Run("authenticated request returns 200", func(t *testing.T) { + status, body := testPostWithWallet(t, app, "/v1/users/me/ping?user_id=7eP5n", wallet, nil, nil) + assert.Equal(t, 200, status, "body: %s", string(body)) + }) + + t.Run("missing user_id returns 400", func(t *testing.T) { + status, _ := testPostWithWallet(t, app, "/v1/users/me/ping", wallet, nil, nil) + assert.Equal(t, 400, status) + }) + + t.Run("unauthenticated request with user_id returns 403", func(t *testing.T) { + status, _ := testPost(t, app, "/v1/users/me/ping?user_id=7eP5n", nil, nil) + assert.Equal(t, 403, status) + }) +} From 7696959b3fb431bef9b8e6f5a4ead32f3282c788 Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 15 Jun 2026 19:11:22 -0700 Subject: [PATCH 3/3] fix(db): make 0218_create_event_routes idempotent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CREATE TABLE IF NOT EXISTS silently skips if the table already exists, but the subsequent ALTER TABLE ADD CONSTRAINT had no guard — causing: ERROR: multiple primary keys for table "event_routes" are not allowed on any DB where the table was already created. Fix by inlining the PRIMARY KEY constraint in the CREATE TABLE definition so the whole statement is skipped under IF NOT EXISTS. This has been blocking bridge auto-upgrades since the 0218 migration was first applied to production (June 9). All migrate-* jobs in the api namespace have been failing, leaving 60+ auto-upgrader CronJob pods stuck in a 30-min kubectl-wait loop. --- ddl/migrations/0218_create_event_routes.sql | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ddl/migrations/0218_create_event_routes.sql b/ddl/migrations/0218_create_event_routes.sql index 3fbb9e3b..a0c1b521 100644 --- a/ddl/migrations/0218_create_event_routes.sql +++ b/ddl/migrations/0218_create_event_routes.sql @@ -4,7 +4,6 @@ -- indexer when an event is created, owner_id points to the event's host user, -- and is_current flags the canonical row so a LEFT JOIN ON is_current = true -- always lands on at most one row per event. - CREATE TABLE IF NOT EXISTS public.event_routes ( slug character varying NOT NULL, owner_id integer NOT NULL, @@ -12,11 +11,8 @@ CREATE TABLE IF NOT EXISTS public.event_routes ( is_current boolean NOT NULL, blockhash character varying NOT NULL, blocknumber integer NOT NULL, - txhash character varying NOT NULL + txhash character varying NOT NULL, + CONSTRAINT event_routes_pkey PRIMARY KEY (owner_id, slug) ); - -ALTER TABLE ONLY public.event_routes - ADD CONSTRAINT event_routes_pkey PRIMARY KEY (owner_id, slug); - CREATE INDEX IF NOT EXISTS event_routes_event_id_idx ON public.event_routes USING btree (event_id);