feat: migrate IM identity and snowflake primary keys

This commit is contained in:
richjohnrambo
2026-08-18 01:15:21 +08:00
parent db322d80dd
commit bf562c7d56
27 changed files with 1071 additions and 482 deletions
+116 -123
View File
@@ -152,7 +152,8 @@ func (a *adapter) TenantUserGet(id t.TenantID, uid t.Uid) (*t.User, error) {
defer cancel()
}
var user t.User
err = a.db.GetContext(ctx, &user, "SELECT * FROM im_users WHERE tenant_id=? AND id=? AND state!=?",
err = a.db.GetContext(ctx, &user, `SELECT tenant_id,id,createdat,updatedat,state,stateat,access,lastseen,useragent,
COALESCE(phone,'') AS phone,public,trusted FROM im_users WHERE tenant_id=? AND id=? AND state!=?`,
id, decodeUID(uid), t.StateDeleted)
if err == sql.ErrNoRows {
return nil, nil
@@ -200,9 +201,11 @@ func (a *adapter) tenantUserGetAllTx(ctx context.Context, tx *sqlx.Tx, id t.Tena
var q string
var params []any
if a.tenantScopedDB {
q, params, _ = sqlx.In("SELECT * FROM im_users WHERE id IN (?) AND state!=?", args, t.StateDeleted)
q, params, _ = sqlx.In(`SELECT id,createdat,updatedat,state,stateat,access,lastseen,useragent,
COALESCE(phone,'') AS phone,public,trusted FROM im_users WHERE id IN (?) AND state!=?`, args, t.StateDeleted)
} else {
q, params, _ = sqlx.In("SELECT * FROM im_users WHERE tenant_id=? AND id IN (?) AND state!=?", id, args, t.StateDeleted)
q, params, _ = sqlx.In(`SELECT tenant_id,id,createdat,updatedat,state,stateat,access,lastseen,useragent,
COALESCE(phone,'') AS phone,public,trusted FROM im_users WHERE tenant_id=? AND id IN (?) AND state!=?`, id, args, t.StateDeleted)
}
query := a.db.Rebind(q)
var rows *sqlx.Rows
@@ -308,9 +311,6 @@ func (a *adapter) TenantUserDelete(id t.TenantID, uid t.Uid, hard bool) error {
if _, err = tx.Exec("DELETE FROM im_credentials WHERE userid=?", decoded); err != nil {
return err
}
if _, err = tx.Exec("DELETE FROM im_usertags WHERE tenant_id=? AND userid=?", id, decoded); err != nil {
return err
}
if _, err = tx.Exec("DELETE FROM im_users WHERE tenant_id=? AND id=?", id, decoded); err != nil {
return err
}
@@ -389,7 +389,11 @@ func (a *adapter) TenantUserUpdate(id t.TenantID, uid t.Uid, update map[string]a
}
}()
decoded := decodeUID(uid)
update = withoutUserTags(update)
cols, args := common.UpdateByMap(update)
if len(cols) == 0 {
return tx.Commit()
}
args = append(args, id, decoded)
res, err := tx.Exec("UPDATE im_users SET "+strings.Join(cols, ",")+" WHERE tenant_id=? AND id=?", args...)
if err != nil {
@@ -404,14 +408,6 @@ func (a *adapter) TenantUserUpdate(id t.TenantID, uid t.Uid, update map[string]a
return err
}
}
if tags := common.ExtractTags(update); tags != nil {
if _, err = tx.Exec("DELETE FROM im_usertags WHERE tenant_id=? AND userid=?", id, decoded); err != nil {
return err
}
if err = addTenantTags(tx, id, "im_usertags", "userid", decoded, tags, false); err != nil {
return err
}
}
return tx.Commit()
}
@@ -426,43 +422,7 @@ func (a *adapter) TenantUserUpdateTags(id t.TenantID, uid t.Uid, add, remove, re
if a.tenantScopedDB {
return a.UserUpdateTags(uid, add, remove, reset)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
}
tx, err := a.db.BeginTxx(ctx, nil)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
tx.Rollback()
}
}()
decoded := decodeUID(uid)
if reset != nil {
if _, err = tx.Exec("DELETE FROM im_usertags WHERE tenant_id=? AND userid=?", id, decoded); err != nil {
return nil, err
}
add, remove = reset, nil
}
if err = addTenantTags(tx, id, "im_usertags", "userid", decoded, add, reset == nil); err != nil {
return nil, err
}
if len(remove) > 0 {
q, params, _ := sqlx.In("DELETE FROM im_usertags WHERE tenant_id=? AND userid=? AND tag IN (?)", id, decoded, remove)
if _, err = tx.Exec(tx.Rebind(q), params...); err != nil {
return nil, err
}
}
var allTags []string
if err = tx.Select(&allTags, "SELECT tag FROM im_usertags WHERE tenant_id=? AND userid=?", id, decoded); err != nil {
return nil, err
}
if _, err = tx.Exec("UPDATE im_users SET tags=? WHERE tenant_id=? AND id=?", t.StringSlice(allTags), id, decoded); err != nil {
return nil, err
}
return allTags, tx.Commit()
return nil, nil
}
func (a *adapter) TenantUserUnreadCount(id t.TenantID, uids ...t.Uid) (map[t.Uid]int, error) {
@@ -1520,7 +1480,7 @@ func (a *adapter) TenantFind(id t.TenantID, caller, promoPrefix string, req [][]
stateConstraint := ""
if activeOnly {
args = append(args, t.StateOK)
stateConstraint = "u.state=? AND "
stateConstraint = "t.state=? AND "
}
index := make(map[string]struct{})
for _, tag := range allTags {
@@ -1531,27 +1491,7 @@ func (a *adapter) TenantFind(id t.TenantID, caller, promoPrefix string, req [][]
if promoPrefix != "" {
matcher = "SUM(CASE WHEN LOCATE('" + promoPrefix + "', tg.tag)=1 THEN 20 ELSE 1 END)"
}
query := "SELECT u.id,u.createdat,u.updatedat,0,u.access,0 AS subcnt,u.public,u.trusted,u.tags," + matcher + " AS matches " +
"FROM im_users AS u JOIN im_usertags AS tg ON tg.tenant_id=u.tenant_id AND tg.userid=u.id " +
"WHERE u.tenant_id=? AND " + stateConstraint + "tg.tag IN (?" + strings.Repeat(",?", len(allTags)-1) + ") " +
"GROUP BY u.id,u.createdat,u.updatedat,u.access,u.public,u.trusted,u.tags "
if len(allReq) > 0 {
q, addArgs := common.DisjunctionSql(req, "tg.tag")
query += q
args = append(args, addArgs...)
}
query += "UNION ALL "
args = append(args, id)
if activeOnly {
args = append(args, t.StateOK)
stateConstraint = "t.state=? AND "
} else {
stateConstraint = ""
}
for _, tag := range allTags {
args = append(args, tag)
}
query += "SELECT t.name AS topic,t.createdat,t.updatedat,t.usebt,t.access,t.subcnt,t.public,t.trusted,t.tags," + matcher + " AS matches " +
query := "SELECT t.name AS topic,t.createdat,t.updatedat,t.usebt,t.access,t.subcnt,t.public,t.trusted,t.tags," + matcher + " AS matches " +
"FROM im_topics AS t JOIN im_topictags AS tg ON t.tenant_id=tg.tenant_id AND t.name=tg.topic " +
"WHERE t.tenant_id=? AND " + stateConstraint + "tg.tag IN (?" + strings.Repeat(",?", len(allTags)-1) + ") " +
"GROUP BY t.name,t.createdat,t.updatedat,t.usebt,t.access,t.subcnt,t.public,t.trusted,t.tags "
@@ -1622,9 +1562,7 @@ func (a *adapter) TenantFindOne(id t.TenantID, tag string) (string, error) {
}
rows, err := a.db.QueryxContext(ctx,
"SELECT tp.name AS topic FROM im_topics AS tp LEFT JOIN im_topictags AS tt ON tp.tenant_id=tt.tenant_id AND tp.name=tt.topic "+
"WHERE tp.tenant_id=? AND tt.tag=? UNION ALL "+
"SELECT u.id AS topic FROM im_users AS u LEFT JOIN im_usertags AS ut ON u.tenant_id=ut.tenant_id AND ut.userid=u.id "+
"WHERE u.tenant_id=? AND ut.tag=? LIMIT 1", id, tag, id, tag)
"WHERE tp.tenant_id=? AND tt.tag=? LIMIT 1", id, tag)
if err != nil {
return "", err
}
@@ -3816,7 +3754,11 @@ func (a *adapter) TenantUserProfileGet(id t.TenantID, uid t.Uid) (*t.UserProfile
if cancel != nil {
defer cancel()
}
if _, err := a.db.ExecContext(ctx, `INSERT IGNORE INTO im_user_profiles(user_id,public_account) VALUES(?,?)`, decodeUID(uid), uid.UserId()); err != nil {
profileID, err := nextSnowflakeID()
if err != nil {
return nil, err
}
if _, err := a.db.ExecContext(ctx, `INSERT IGNORE INTO im_user_profiles(id,user_id,public_account) VALUES(?,?,?)`, profileID, decodeUID(uid), uid.UserId()); err != nil {
return nil, err
}
return a.userProfileByUID(ctx, uid)
@@ -3839,7 +3781,11 @@ func (a *adapter) TenantUserProfileUpdate(id t.TenantID, uid t.Uid, patch t.User
if cancel != nil {
defer cancel()
}
if _, err := a.db.ExecContext(ctx, `INSERT IGNORE INTO im_user_profiles(user_id,public_account) VALUES(?,?)`, decodeUID(uid), uid.UserId()); err != nil {
profileID, err := nextSnowflakeID()
if err != nil {
return nil, err
}
if _, err := a.db.ExecContext(ctx, `INSERT IGNORE INTO im_user_profiles(id,user_id,public_account) VALUES(?,?,?)`, profileID, decodeUID(uid), uid.UserId()); err != nil {
return nil, err
}
sets := []string{"version=version+1", "updated_at=CURRENT_TIMESTAMP(3)"}
@@ -3873,6 +3819,10 @@ func (a *adapter) TenantUserProfileUpdate(id t.TenantID, uid t.Uid, patch t.User
sets = append(sets, "region=?")
args = append(args, strings.TrimSpace(*patch.Region))
}
if patch.Email != nil {
sets = append(sets, "email=?")
args = append(args, strings.TrimSpace(*patch.Email))
}
args = append(args, decodeUID(uid), patch.Version)
res, err := a.db.ExecContext(ctx, `UPDATE im_user_profiles SET `+strings.Join(sets, ",")+` WHERE user_id=? AND version=?`, args...)
if err != nil {
@@ -3902,7 +3852,11 @@ func (a *adapter) TenantUserPrivacyGet(id t.TenantID, uid t.Uid) (*t.UserPrivacy
if cancel != nil {
defer cancel()
}
if _, err := a.db.ExecContext(ctx, `INSERT IGNORE INTO im_user_privacy_settings(user_id,add_me_methods) VALUES(?,'{"account":true,"phone":true,"qr":true,"group":true}')`, decodeUID(uid)); err != nil {
privacyID, err := nextSnowflakeID()
if err != nil {
return nil, err
}
if _, err := a.db.ExecContext(ctx, `INSERT IGNORE INTO im_user_privacy_settings(id,user_id,add_me_methods) VALUES(?,?,'{"account":true,"phone":true,"qr":true,"group":true}')`, privacyID, decodeUID(uid)); err != nil {
return nil, err
}
return a.userPrivacyByUID(ctx, uid)
@@ -3925,7 +3879,11 @@ func (a *adapter) TenantUserPrivacyUpdate(id t.TenantID, uid t.Uid, patch t.User
if cancel != nil {
defer cancel()
}
if _, err := a.db.ExecContext(ctx, `INSERT IGNORE INTO im_user_privacy_settings(user_id,add_me_methods) VALUES(?,'{"account":true,"phone":true,"qr":true,"group":true}')`, decodeUID(uid)); err != nil {
privacyID, err := nextSnowflakeID()
if err != nil {
return nil, err
}
if _, err := a.db.ExecContext(ctx, `INSERT IGNORE INTO im_user_privacy_settings(id,user_id,add_me_methods) VALUES(?,?,'{"account":true,"phone":true,"qr":true,"group":true}')`, privacyID, decodeUID(uid)); err != nil {
return nil, err
}
sets := []string{"version=version+1", "updated_at=CURRENT_TIMESTAMP(3)"}
@@ -4048,12 +4006,16 @@ func (a *adapter) TenantDevicePushTokenUpsert(id t.TenantID, token *t.DevicePush
token.Token = strings.TrimSpace(token.Token)
token.AppVersion = strings.TrimSpace(token.AppVersion)
token.Platform = strings.ToLower(strings.TrimSpace(token.Platform))
_, err := a.db.ExecContext(ctx,
`INSERT INTO im_device_push_tokens(device_id,user_id,provider,token,app_version,platform,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?)
tokenID, err := nextSnowflakeID()
if err != nil {
return nil, err
}
_, err = a.db.ExecContext(ctx,
`INSERT INTO im_device_push_tokens(id,device_id,user_id,provider,token,app_version,platform,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE device_id=VALUES(device_id),user_id=VALUES(user_id),provider=VALUES(provider),token=VALUES(token),
app_version=VALUES(app_version),platform=VALUES(platform),updated_at=VALUES(updated_at)`,
token.DeviceID, decodeUID(token.UserID), token.Provider, token.Token, token.AppVersion, token.Platform, now, now)
tokenID, token.DeviceID, decodeUID(token.UserID), token.Provider, token.Token, token.AppVersion, token.Platform, now, now)
if err != nil {
return nil, err
}
@@ -4515,12 +4477,14 @@ func (a *adapter) userProfileByUID(ctx context.Context, uid t.Uid) (*t.UserProfi
Signature string
Gender string
Region string
Email string
PublicAccount string `db:"public_account"`
Version int
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}{}
if err := sqlx.GetContext(ctx, a.db, &row, `SELECT * FROM im_user_profiles WHERE user_id=?`, decodeUID(uid)); err != nil {
if err := sqlx.GetContext(ctx, a.db, &row, `SELECT user_id,avatar_file_id,nickname,birth_date,signature,gender,region,email,
public_account,version,created_at,updated_at FROM im_user_profiles WHERE user_id=?`, decodeUID(uid)); err != nil {
return nil, err
}
profile := &t.UserProfile{
@@ -4530,6 +4494,7 @@ func (a *adapter) userProfileByUID(ctx context.Context, uid t.Uid) (*t.UserProfi
Signature: row.Signature,
Gender: row.Gender,
Region: row.Region,
Email: row.Email,
PublicAccount: row.PublicAccount,
Version: row.Version,
CreatedAt: row.CreatedAt,
@@ -4552,7 +4517,8 @@ func (a *adapter) userPrivacyByUID(ctx context.Context, uid t.Uid) (*t.UserPriva
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}{}
if err := sqlx.GetContext(ctx, a.db, &row, `SELECT * FROM im_user_privacy_settings WHERE user_id=?`, decodeUID(uid)); err != nil {
if err := sqlx.GetContext(ctx, a.db, &row, `SELECT user_id,add_me_methods,profile_visibility,last_seen_visibility,
read_receipts,version,created_at,updated_at FROM im_user_privacy_settings WHERE user_id=?`, decodeUID(uid)); err != nil {
return nil, err
}
settings := &t.UserPrivacySettings{
@@ -5615,11 +5581,15 @@ func (a *adapter) TenantUserSecurityGetAuthVersion(id t.TenantID, uid t.Uid) (in
}
decoded := decodeUID(uid)
now := t.TimeNow()
_, err := a.db.ExecContext(ctx,
`INSERT INTO im_user_security(user_id,auth_version,created_at,updated_at)
VALUES(?,?,?,?)
securityID, err := nextSnowflakeID()
if err != nil {
return 0, err
}
_, err = a.db.ExecContext(ctx,
`INSERT INTO im_user_security(id,user_id,auth_version,created_at,updated_at)
VALUES(?,?,?,?,?)
ON DUPLICATE KEY UPDATE auth_version=auth_version`,
decoded, 1, now, now)
securityID, decoded, 1, now, now)
if err != nil {
return 0, err
}
@@ -5666,14 +5636,18 @@ func (a *adapter) TenantUserSecurityBumpAuthVersion(id t.TenantID, uid t.Uid, up
}
}()
decoded := decodeUID(uid)
securityID, err := nextSnowflakeID()
if err != nil {
return 0, err
}
if _, err = tx.ExecContext(ctx,
`INSERT INTO im_user_security(user_id,auth_version,password_updated_at,created_at,updated_at)
VALUES(?,?,?,?,?)
`INSERT INTO im_user_security(id,user_id,auth_version,password_updated_at,created_at,updated_at)
VALUES(?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE
auth_version=auth_version+1,
password_updated_at=VALUES(password_updated_at),
updated_at=VALUES(updated_at)`,
decoded, 2, updatedAt, updatedAt, updatedAt); err != nil {
securityID, decoded, 2, updatedAt, updatedAt, updatedAt); err != nil {
return 0, err
}
var version int
@@ -5911,12 +5885,16 @@ func (a *adapter) TenantIndependentPasswordUpsert(id t.TenantID, pass *t.Indepen
now := t.TimeNow()
pass.CreatedAt = now
pass.UpdatedAt = now
_, err := a.db.ExecContext(ctx,
settingsID, err := nextSnowflakeID()
if err != nil {
return err
}
_, err = a.db.ExecContext(ctx,
`INSERT INTO im_youth_mode_settings
(user_id,purpose,password_hash,failed_attempts,locked_until,created_at,updated_at)
VALUES(?,?,?,0,NULL,?,?)
(id,user_id,purpose,password_hash,failed_attempts,locked_until,created_at,updated_at)
VALUES(?,?,?,?,0,NULL,?,?)
ON DUPLICATE KEY UPDATE password_hash=VALUES(password_hash),failed_attempts=0,locked_until=NULL,updated_at=VALUES(updated_at)`,
decodeUID(pass.UserID), pass.Purpose, pass.PasswordHash, pass.CreatedAt, pass.UpdatedAt)
settingsID, decodeUID(pass.UserID), pass.Purpose, pass.PasswordHash, pass.CreatedAt, pass.UpdatedAt)
return err
}
@@ -6478,10 +6456,14 @@ func (a *adapter) TenantFriendRequestAccept(id t.TenantID, requestID string, act
row.UpdatedAt = handledAt
}
for _, pair := range [][2]t.Uid{{applicant, target}, {target, applicant}} {
friendshipID, idErr := nextSnowflakeID()
if idErr != nil {
return nil, idErr
}
if _, err = tx.ExecContext(ctx,
"INSERT INTO im_friendships(user_id,peer_id,status,topic,created_at,updated_at) VALUES(?,?,?,?,?,?) "+
"INSERT INTO im_friendships(id,user_id,peer_id,status,topic,created_at,updated_at) VALUES(?,?,?,?,?,?,?) "+
"ON DUPLICATE KEY UPDATE status=VALUES(status),topic=VALUES(topic),updated_at=VALUES(updated_at)",
decodeUID(pair[0]), decodeUID(pair[1]), t.RelationshipFriend, topic, handledAt, handledAt); err != nil {
friendshipID, decodeUID(pair[0]), decodeUID(pair[1]), t.RelationshipFriend, topic, handledAt, handledAt); err != nil {
return nil, err
}
}
@@ -6642,10 +6624,14 @@ func (a *adapter) TenantFriendshipUpsertPair(id t.TenantID, uid1, uid2 t.Uid, to
defer cancel()
}
for _, pair := range [][2]t.Uid{{uid1, uid2}, {uid2, uid1}} {
friendshipID, err := nextSnowflakeID()
if err != nil {
return err
}
if _, err := a.db.ExecContext(ctx,
"INSERT INTO im_friendships(user_id,peer_id,status,topic,created_at,updated_at) VALUES(?,?,?,?,?,?) "+
"INSERT INTO im_friendships(id,user_id,peer_id,status,topic,created_at,updated_at) VALUES(?,?,?,?,?,?,?) "+
"ON DUPLICATE KEY UPDATE status=VALUES(status),topic=VALUES(topic),updated_at=VALUES(updated_at)",
decodeUID(pair[0]), decodeUID(pair[1]), t.RelationshipFriend, topic, now, now); err != nil {
friendshipID, decodeUID(pair[0]), decodeUID(pair[1]), t.RelationshipFriend, topic, now, now); err != nil {
return err
}
}
@@ -6680,13 +6666,13 @@ func (a *adapter) TenantFriendshipList(id t.TenantID, uid t.Uid, queryText, init
}
if q := strings.TrimSpace(queryText); q != "" {
like := "%" + q + "%"
where = append(where, "(fs.remark LIKE ? OR CAST(u.public AS CHAR) LIKE ? OR CAST(u.tags AS CHAR) LIKE ?)")
args = append(args, like, like, like)
where = append(where, "(fs.remark LIKE ? OR p.nickname LIKE ? OR p.public_account LIKE ? OR CAST(u.public AS CHAR) LIKE ?)")
args = append(args, like, like, like, like)
}
if initial = strings.TrimSpace(initial); initial != "" {
like := initial + "%"
where = append(where, "(fs.remark LIKE ? OR CAST(u.public AS CHAR) LIKE ?)")
args = append(args, like, like)
where = append(where, "(fs.remark LIKE ? OR p.nickname LIKE ? OR CAST(u.public AS CHAR) LIKE ?)")
args = append(args, like, like, like)
}
args = append(args, limit+1)
ctx, cancel := a.getContext()
@@ -6696,6 +6682,7 @@ func (a *adapter) TenantFriendshipList(id t.TenantID, uid t.Uid, queryText, init
rows, err := a.db.QueryxContext(ctx, `SELECT fs.*,u.public,u.trusted
FROM im_friendships AS fs
JOIN im_users AS u ON u.id=fs.peer_id
LEFT JOIN im_user_profiles AS p ON p.user_id=u.id
WHERE `+strings.Join(where, " AND ")+`
ORDER BY fs.peer_id ASC LIMIT ?`, args...)
if err != nil {
@@ -6776,7 +6763,8 @@ func (a *adapter) TenantFriendshipGet(id t.TenantID, userID, peerID t.Uid) (*t.F
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}{}
err := a.db.GetContext(ctx, &row, "SELECT * FROM im_friendships WHERE user_id=? AND peer_id=?",
err := a.db.GetContext(ctx, &row, `SELECT user_id,peer_id,status,remark,topic,created_at,updated_at
FROM im_friendships WHERE user_id=? AND peer_id=?`,
decodeUID(userID), decodeUID(peerID))
if err == sql.ErrNoRows {
return nil, nil
@@ -6871,7 +6859,8 @@ func (a *adapter) TenantUserBlockGet(id t.TenantID, blockerID, blockedID t.Uid)
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}{}
err := a.db.GetContext(ctx, &row, "SELECT * FROM im_user_blocks WHERE blocker_id=? AND blocked_id=?",
err := a.db.GetContext(ctx, &row, `SELECT blocker_id,blocked_id,created_at,updated_at
FROM im_user_blocks WHERE blocker_id=? AND blocked_id=?`,
decodeUID(blockerID), decodeUID(blockedID))
if err == sql.ErrNoRows {
return nil, nil
@@ -6919,7 +6908,7 @@ func (a *adapter) TenantUserBlockList(id t.TenantID, blockerID t.Uid, cursor str
if cancel != nil {
defer cancel()
}
rows, err := a.db.QueryxContext(ctx, `SELECT b.*,u.public,u.trusted
rows, err := a.db.QueryxContext(ctx, `SELECT b.blocker_id,b.blocked_id,b.created_at,b.updated_at,u.public,u.trusted
FROM im_user_blocks AS b
LEFT JOIN im_users AS u ON u.id=b.blocked_id
WHERE `+strings.Join(where, " AND ")+`
@@ -6986,10 +6975,14 @@ func (a *adapter) TenantUserBlockUpsert(id t.TenantID, blockerID, blockedID t.Ui
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx,
"INSERT INTO im_user_blocks(blocker_id,blocked_id,created_at,updated_at) VALUES(?,?,?,?) "+
blockID, err := nextSnowflakeID()
if err != nil {
return nil, err
}
_, err = a.db.ExecContext(ctx,
"INSERT INTO im_user_blocks(id,blocker_id,blocked_id,created_at,updated_at) VALUES(?,?,?,?,?) "+
"ON DUPLICATE KEY UPDATE updated_at=VALUES(updated_at)",
decodeUID(blockerID), decodeUID(blockedID), now, now)
blockID, decodeUID(blockerID), decodeUID(blockedID), now, now)
if err != nil {
return nil, err
}
@@ -7048,24 +7041,23 @@ func (a *adapter) TenantUserSearch(id t.TenantID, viewer t.Uid, queryText, searc
where = append(where, "u.id>?")
args = append(args, parsed)
}
joins := []string{"LEFT JOIN im_user_privacy_settings AS privacy ON privacy.user_id=u.id"}
joins := []string{
"LEFT JOIN im_user_privacy_settings AS privacy ON privacy.user_id=u.id",
"LEFT JOIN im_user_profiles AS profile ON profile.user_id=u.id",
}
addMethod := "account"
switch searchType {
case "", "account":
like := "%" + queryText + "%"
joins = append(joins, "LEFT JOIN im_usertags AS ut ON ut.userid=u.id")
where = append(where, "(ut.tag LIKE ? OR CAST(u.public AS CHAR) LIKE ? OR u.id=?)")
args = append(args, like, like, userIDNumericArg(queryText))
where = append(where, "(profile.nickname LIKE ? OR profile.public_account LIKE ? OR CAST(u.public AS CHAR) LIKE ? OR u.id=?)")
args = append(args, like, like, like, userIDNumericArg(queryText))
case "exact_account":
joins = append(joins, "LEFT JOIN im_usertags AS ut ON ut.userid=u.id")
where = append(where, "(ut.tag=? OR u.id=?)")
args = append(args, queryText, userIDNumericArg(queryText))
joins = append(joins, "LEFT JOIN im_auth AS account_auth ON account_auth.userid=u.id AND account_auth.scheme='basic'")
where = append(where, "(profile.public_account=? OR account_auth.uname=? OR u.id=?)")
args = append(args, queryText, strings.TrimPrefix(queryText, "basic:"), userIDNumericArg(queryText))
case "phone":
addMethod = "phone"
where = append(where, `EXISTS (
SELECT 1 FROM im_credentials AS c
WHERE c.userid=u.id AND c.method='tel' AND c.value=? AND c.done=true
)`)
where = append(where, "u.phone=?")
args = append(args, queryText)
default:
return nil, "", t.ErrMalformed
@@ -7080,7 +7072,8 @@ func (a *adapter) TenantUserSearch(id t.TenantID, viewer t.Uid, queryText, searc
if cancel != nil {
defer cancel()
}
rows, err := a.db.QueryxContext(ctx, `SELECT DISTINCT u.* FROM im_users AS u `+strings.Join(joins, " ")+`
rows, err := a.db.QueryxContext(ctx, `SELECT DISTINCT u.id,u.createdat,u.updatedat,u.state,u.stateat,u.access,u.lastseen,u.useragent,
COALESCE(u.phone,'') AS phone,u.public,u.trusted FROM im_users AS u `+strings.Join(joins, " ")+`
WHERE `+strings.Join(where, " AND ")+` ORDER BY u.id ASC LIMIT ?`, args...)
if err != nil {
return nil, "", err