fix: auto-provision im_user_privacy_settings columns on startup
Zentao #24/#25: commit 50f8581 added friend_request_verification and group_invite_verification to userPrivacyByUID, but existing databases lack those columns, so GetPrivacy failed with Error 1054 and every cross-user profile/qrcodes/friend-request endpoint returned 500.
Add user_privacy_schema.go which, under GET_LOCK, checks information_schema and ALTERs in any missing privacy columns, wired into the root adapter Open() and per-tenant TenantAdapterFor so tenant-scoped databases are provisioned too.
This commit is contained in:
@@ -284,6 +284,9 @@ func (a *adapter) Open(jsonconfig json.RawMessage) error {
|
|||||||
return errors.New("mysql adapter failed to open tenant registry database: " + err.Error())
|
return errors.New("mysql adapter failed to open tenant registry database: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err = ensureUserPrivacySchema(a.db); err != nil {
|
||||||
|
return errors.New("mysql adapter failed to ensure user privacy schema: " + err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -494,6 +497,10 @@ func (a *adapter) TenantAdapterFor(tenantID t.TenantID) (dbadapter.TenantBusines
|
|||||||
db.Close()
|
db.Close()
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
if err = ensureUserPrivacySchema(db); err != nil {
|
||||||
|
db.Close()
|
||||||
|
return nil, nil, errors.New("mysql adapter failed to ensure user privacy schema for tenant: " + err.Error())
|
||||||
|
}
|
||||||
registryDB := a.registryDB
|
registryDB := a.registryDB
|
||||||
if registryDB == nil {
|
if registryDB == nil {
|
||||||
registryDB = a.db
|
registryDB = a.db
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
//go:build mysql
|
||||||
|
// +build mysql
|
||||||
|
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
const userPrivacyMigrationLock = "CONCAT('im_user_privacy:', LEFT(SHA2(DATABASE(), 256), 40))"
|
||||||
|
|
||||||
|
// ensureUserPrivacySchema adds columns of im_user_privacy_settings that were
|
||||||
|
// introduced after the table's initial release. Databases created fresh by
|
||||||
|
// createIMUserProductTables already have them; legacy databases are upgraded
|
||||||
|
// in place. A missing table is skipped: it is created by the fresh-install
|
||||||
|
// path and there is nothing to upgrade yet.
|
||||||
|
func ensureUserPrivacySchema(db *sqlx.DB) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
conn, err := db.Connx(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
var locked sql.NullInt64
|
||||||
|
if err = conn.QueryRowContext(ctx, "SELECT GET_LOCK("+userPrivacyMigrationLock+", 60)").Scan(&locked); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !locked.Valid || locked.Int64 != 1 {
|
||||||
|
return errors.New("mysql: timed out waiting for user privacy migration lock")
|
||||||
|
}
|
||||||
|
defer conn.ExecContext(ctx, "SELECT RELEASE_LOCK("+userPrivacyMigrationLock+")")
|
||||||
|
|
||||||
|
tableExists, err := identityTableExists(ctx, conn, "im_user_privacy_settings")
|
||||||
|
if err != nil || !tableExists {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Column definitions mirror createIMUserProductTables; the SELECT in
|
||||||
|
// userPrivacyByUID references every one of them.
|
||||||
|
columns := []struct{ name, ddl string }{
|
||||||
|
{"profile_visibility", "VARCHAR(32) NOT NULL DEFAULT 'friends'"},
|
||||||
|
{"last_seen_visibility", "VARCHAR(32) NOT NULL DEFAULT 'friends'"},
|
||||||
|
{"read_receipts", "TINYINT NOT NULL DEFAULT 1"},
|
||||||
|
{"friend_request_verification", "TINYINT NOT NULL DEFAULT 1"},
|
||||||
|
{"group_invite_verification", "TINYINT NOT NULL DEFAULT 0"},
|
||||||
|
}
|
||||||
|
for _, col := range columns {
|
||||||
|
exists, err := identityColumnExists(ctx, conn, "im_user_privacy_settings", col.name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
if _, err = conn.ExecContext(ctx, "ALTER TABLE im_user_privacy_settings ADD COLUMN "+col.name+" "+col.ddl); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user