From be61ec2b71616c65140a1800cc8a45bcbe2e7f23 Mon Sep 17 00:00:00 2001 From: richjohnrambo Date: Wed, 9 Sep 2026 15:34:20 +0800 Subject: [PATCH] fix: backfill user public profile projections --- server/db/mysql/user_identity_schema.go | 42 +++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/server/db/mysql/user_identity_schema.go b/server/db/mysql/user_identity_schema.go index 8ffe3f1..d36c8c8 100644 --- a/server/db/mysql/user_identity_schema.go +++ b/server/db/mysql/user_identity_schema.go @@ -111,6 +111,9 @@ func ensureUserIdentitySchema(db *sqlx.DB) error { if err = backfillProfileDisplay(ctx, conn, usersScoped); err != nil { return err } + if err = backfillUserPublicFromProfile(ctx, conn, usersScoped); err != nil { + return err + } } indexName := "users_phone" @@ -464,6 +467,45 @@ func backfillProfileDisplay(ctx context.Context, conn *sqlx.Conn, usersScoped bo return err } +func backfillUserPublicFromProfile(ctx context.Context, conn *sqlx.Conn, usersScoped bool) error { + profilesScoped, err := identityColumnExists(ctx, conn, "im_user_profiles", "tenant_id") + if err != nil { + return err + } + if profilesScoped != usersScoped { + return errors.New("mysql: im_users and im_user_profiles tenant scope mismatch") + } + publicDoc := "COALESCE(NULLIF(u.public,''), JSON_OBJECT())" + nicknamePatch := `u.public=JSON_SET(` + publicDoc + `, + '$.display_name',p.nickname,'$.nickname',p.nickname,'$.fn',p.nickname,'$.name',p.nickname)` + avatarPatch := `u.public=JSON_SET(` + publicDoc + `,'$.avatar_file_id',p.avatar_file_id)` + accountPatch := `u.public=JSON_SET(` + publicDoc + `,'$.public_account',p.public_account)` + join := "JOIN im_users AS u ON u.id=p.user_id" + if usersScoped { + join = "JOIN im_users AS u ON u.tenant_id=p.tenant_id AND u.id=p.user_id" + } + for _, query := range []string{ + `UPDATE im_user_profiles AS p ` + join + ` + SET ` + nicknamePatch + ` + WHERE p.nickname<>'' AND ( + COALESCE(JSON_UNQUOTE(JSON_EXTRACT(u.public,'$.display_name')),'')<>p.nickname OR + COALESCE(JSON_UNQUOTE(JSON_EXTRACT(u.public,'$.nickname')),'')<>p.nickname OR + COALESCE(JSON_UNQUOTE(JSON_EXTRACT(u.public,'$.fn')),'')<>p.nickname OR + COALESCE(JSON_UNQUOTE(JSON_EXTRACT(u.public,'$.name')),'')<>p.nickname)`, + `UPDATE im_user_profiles AS p ` + join + ` + SET ` + avatarPatch + ` + WHERE p.avatar_file_id<>'' AND COALESCE(JSON_UNQUOTE(JSON_EXTRACT(u.public,'$.avatar_file_id')),'')<>p.avatar_file_id`, + `UPDATE im_user_profiles AS p ` + join + ` + SET ` + accountPatch + ` + WHERE p.public_account<>'' AND COALESCE(JSON_UNQUOTE(JSON_EXTRACT(u.public,'$.public_account')),'')<>p.public_account`, + } { + if _, err = conn.ExecContext(ctx, query); err != nil { + return err + } + } + return nil +} + func identityCandidates(ctx context.Context, conn *sqlx.Conn, scoped bool, method string) ([]identityValue, error) { var out []identityValue appendQuery := func(query string, args ...any) error {