refactor: read user profile fields from profile table
This commit is contained in:
@@ -59,7 +59,6 @@ type profileUserRow struct {
|
||||
Phone string `db:"phone"`
|
||||
LastSeen sql.NullTime `db:"lastseen"`
|
||||
UserAgent string `db:"useragent"`
|
||||
Public any `db:"public"`
|
||||
Trusted any `db:"trusted"`
|
||||
ProfileNickname sql.NullString `db:"profile_nickname"`
|
||||
ProfileAvatarFileID sql.NullString `db:"profile_avatar_file_id"`
|
||||
@@ -86,7 +85,7 @@ func (row profileUserRow) lastSeen() *time.Time {
|
||||
}
|
||||
|
||||
func (row profileUserRow) profilePublic() any {
|
||||
return profilePublicFromFields(common.FromJSON(row.Public), row.ProfileNickname, row.ProfileAvatarFileID, row.ProfileSignature, row.ProfileGender, row.ProfileRegion, row.ProfilePublicAccount)
|
||||
return profilePublicFromFields(row.ProfileNickname, row.ProfileAvatarFileID, row.ProfileSignature, row.ProfileGender, row.ProfileRegion, row.ProfilePublicAccount)
|
||||
}
|
||||
|
||||
func profileUserFromRow(row profileUserRow) t.User {
|
||||
@@ -111,9 +110,8 @@ func profileUserFromRow(row profileUserRow) t.User {
|
||||
return user
|
||||
}
|
||||
|
||||
func profilePublicFromFields(base any, nickname, avatarFileID, signature, gender, region, publicAccount sql.NullString) any {
|
||||
public := publicMap(base)
|
||||
clearProfilePublicFields(public)
|
||||
func profilePublicFromFields(nickname, avatarFileID, signature, gender, region, publicAccount sql.NullString) any {
|
||||
public := map[string]any{}
|
||||
if nickname.Valid {
|
||||
value := strings.TrimSpace(nickname.String)
|
||||
if value != "" {
|
||||
@@ -181,10 +179,11 @@ func ensurePrivateMutationVersion(private any, version int64) any {
|
||||
return data
|
||||
}
|
||||
|
||||
func clearProfilePublicFields(public map[string]any) {
|
||||
for _, key := range []string{"display_name", "nickname", "fn", "name", "avatar_file_id", "photo", "avatar", "signature", "gender", "region", "public_account"} {
|
||||
delete(public, key)
|
||||
}
|
||||
func sanitizeUserUpdate(update map[string]any) map[string]any {
|
||||
update = withoutUserTags(update)
|
||||
delete(update, "Public")
|
||||
delete(update, "public")
|
||||
return update
|
||||
}
|
||||
|
||||
func profileSeedFromPublic(public any) (nickname, avatarFileID string) {
|
||||
@@ -403,7 +402,7 @@ func (a *adapter) TenantUserGet(id t.TenantID, uid t.Uid) (*t.User, error) {
|
||||
}
|
||||
var row profileUserRow
|
||||
err = a.db.GetContext(ctx, &row, `SELECT ? AS tenant_id,u.id,u.username,u.createdat,u.updatedat,u.state,u.stateat,u.access,u.lastseen,u.useragent,
|
||||
COALESCE(u.phone,'') AS phone,u.public,u.trusted,
|
||||
COALESCE(u.phone,'') AS phone,u.trusted,
|
||||
p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature,
|
||||
p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account,p.updated_at AS profile_updated_at
|
||||
FROM im_users AS u LEFT JOIN im_user_profiles AS p ON p.user_id=u.id
|
||||
@@ -493,10 +492,18 @@ func (a *adapter) tenantUserGetAllTx(ctx context.Context, tx *sqlx.Tx, id t.Tena
|
||||
var params []any
|
||||
if a.tenantScopedDB {
|
||||
q, params, _ = sqlx.In(`SELECT id,username,createdat,updatedat,state,stateat,access,lastseen,useragent,
|
||||
COALESCE(phone,'') AS phone,public,trusted FROM im_users WHERE id IN (?) AND state!=?`, args, t.StateDeleted)
|
||||
COALESCE(phone,'') AS phone,trusted,
|
||||
p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature,
|
||||
p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account,p.updated_at AS profile_updated_at
|
||||
FROM im_users AS u LEFT JOIN im_user_profiles AS p ON p.user_id=u.id
|
||||
WHERE u.id IN (?) AND u.state!=?`, args, t.StateDeleted)
|
||||
} else {
|
||||
q, params, _ = sqlx.In(`SELECT tenant_id,id,username,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)
|
||||
q, params, _ = sqlx.In(`SELECT u.tenant_id,u.id,u.username,u.createdat,u.updatedat,u.state,u.stateat,u.access,u.lastseen,u.useragent,
|
||||
COALESCE(u.phone,'') AS phone,u.trusted,
|
||||
p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature,
|
||||
p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account,p.updated_at AS profile_updated_at
|
||||
FROM im_users AS u LEFT JOIN im_user_profiles AS p ON p.tenant_id=u.tenant_id AND p.user_id=u.id
|
||||
WHERE u.tenant_id=? AND u.id IN (?) AND u.state!=?`, id, args, t.StateDeleted)
|
||||
}
|
||||
query := a.db.Rebind(q)
|
||||
var rows *sqlx.Rows
|
||||
@@ -513,12 +520,11 @@ func (a *adapter) tenantUserGetAllTx(ctx context.Context, tx *sqlx.Tx, id t.Tena
|
||||
|
||||
var users []t.User
|
||||
for rows.Next() {
|
||||
var user t.User
|
||||
if err = rows.StructScan(&user); err != nil {
|
||||
var row profileUserRow
|
||||
if err = rows.StructScan(&row); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scanTenantUser(&user)
|
||||
users = append(users, user)
|
||||
users = append(users, profileUserFromRow(row))
|
||||
}
|
||||
return users, rows.Err()
|
||||
}
|
||||
@@ -680,7 +686,7 @@ func (a *adapter) TenantUserUpdate(id t.TenantID, uid t.Uid, update map[string]a
|
||||
}
|
||||
}()
|
||||
decoded := decodeUID(uid)
|
||||
update = withoutUserTags(update)
|
||||
update = sanitizeUserUpdate(update)
|
||||
cols, args := common.UpdateByMap(update)
|
||||
if len(cols) == 0 {
|
||||
return tx.Commit()
|
||||
@@ -1080,7 +1086,7 @@ func (a *adapter) TenantTopicsForUser(id t.TenantID, uid t.Uid, keepDeleted bool
|
||||
}
|
||||
}
|
||||
if len(usrq) > 0 {
|
||||
q = `SELECT u.tenant_id,u.id,u.updatedat,u.state,u.access,u.lastseen,u.useragent,u.public,u.trusted,
|
||||
q = `SELECT u.tenant_id,u.id,u.updatedat,u.state,u.access,u.lastseen,u.useragent,u.trusted,
|
||||
p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature,
|
||||
p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account,p.updated_at AS profile_updated_at,
|
||||
fs.remark AS friendship_remark
|
||||
@@ -1147,7 +1153,7 @@ func (a *adapter) TenantUsersForTopic(id t.TenantID, topic string, keepDeleted b
|
||||
}
|
||||
tcat := t.GetTopicCat(topic)
|
||||
q := `SELECT s.tenant_id,s.createdat,s.updatedat,s.deletedat,s.userid,s.topic,s.delid,s.recvseqid,
|
||||
s.readseqid,s.modewant,s.modegiven,u.public,u.trusted,u.lastseen,u.useragent,s.private,
|
||||
s.readseqid,s.modewant,s.modegiven,u.trusted,u.lastseen,u.useragent,s.private,
|
||||
p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature,
|
||||
p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account
|
||||
FROM im_subscriptions AS s JOIN im_users AS u ON s.tenant_id=u.tenant_id AND s.userid=u.id
|
||||
@@ -1191,18 +1197,18 @@ func (a *adapter) TenantUsersForTopic(id t.TenantID, topic string, keepDeleted b
|
||||
for rows.Next() {
|
||||
var sub t.Subscription
|
||||
var lastSeen sql.NullTime
|
||||
var public, trusted any
|
||||
var trusted any
|
||||
var profileNickname, profileAvatarFileID, profileSignature, profileGender, profileRegion, profilePublicAccount sql.NullString
|
||||
if err = rows.Scan(&sub.TenantID, &sub.CreatedAt, &sub.UpdatedAt, &sub.DeletedAt,
|
||||
&sub.User, &sub.Topic, &sub.DelId, &sub.RecvSeqId, &sub.ReadSeqId, &sub.ModeWant, &sub.ModeGiven,
|
||||
&public, &trusted, &lastSeen, &userAgent, &sub.Private,
|
||||
&trusted, &lastSeen, &userAgent, &sub.Private,
|
||||
&profileNickname, &profileAvatarFileID, &profileSignature,
|
||||
&profileGender, &profileRegion, &profilePublicAccount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sub.User = common.EncodeUidString(sub.User).String()
|
||||
sub.Private = common.FromJSON(sub.Private)
|
||||
sub.SetPublic(profilePublicFromFields(common.FromJSON(public), profileNickname, profileAvatarFileID, profileSignature, profileGender, profileRegion, profilePublicAccount))
|
||||
sub.SetPublic(profilePublicFromFields(profileNickname, profileAvatarFileID, profileSignature, profileGender, profileRegion, profilePublicAccount))
|
||||
sub.SetTrusted(common.FromJSON(trusted))
|
||||
sub.SetLastSeenAndUA(&lastSeen.Time, userAgent)
|
||||
subs = append(subs, sub)
|
||||
@@ -6280,9 +6286,12 @@ func (a *adapter) TenantFriendRequestList(id t.TenantID, uid t.Uid, direction, s
|
||||
args = append(args, parsed)
|
||||
}
|
||||
args = append(args, limit+1)
|
||||
query := `SELECT fr.*,u.public,u.trusted
|
||||
query := `SELECT fr.*,u.trusted,
|
||||
p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature,
|
||||
p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account
|
||||
FROM im_friend_requests AS fr
|
||||
JOIN im_users AS u ON u.id=IF(fr.applicant_id=?,fr.target_id,fr.applicant_id)
|
||||
LEFT JOIN im_user_profiles AS p ON p.user_id=u.id
|
||||
WHERE ` + strings.Join(where, " AND ") + `
|
||||
ORDER BY fr.id DESC LIMIT ?`
|
||||
args = append([]any{decodedUID}, args...)
|
||||
@@ -6299,21 +6308,26 @@ func (a *adapter) TenantFriendRequestList(id t.TenantID, uid t.Uid, direction, s
|
||||
nextCursor := ""
|
||||
for rows.Next() {
|
||||
row := struct {
|
||||
ID int64
|
||||
RequestID string `db:"request_id"`
|
||||
ApplicantID int64 `db:"applicant_id"`
|
||||
TargetID int64 `db:"target_id"`
|
||||
Message string
|
||||
Source string
|
||||
SourceTopic string `db:"source_topic"`
|
||||
Status string
|
||||
IdempotencyKey string `db:"idempotency_key"`
|
||||
ExpiresAt time.Time `db:"expires_at"`
|
||||
HandledAt *time.Time `db:"handled_at"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Public any
|
||||
Trusted any
|
||||
ID int64
|
||||
RequestID string `db:"request_id"`
|
||||
ApplicantID int64 `db:"applicant_id"`
|
||||
TargetID int64 `db:"target_id"`
|
||||
Message string
|
||||
Source string
|
||||
SourceTopic string `db:"source_topic"`
|
||||
Status string
|
||||
IdempotencyKey string `db:"idempotency_key"`
|
||||
ExpiresAt time.Time `db:"expires_at"`
|
||||
HandledAt *time.Time `db:"handled_at"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Trusted any
|
||||
ProfileNickname sql.NullString `db:"profile_nickname"`
|
||||
ProfileAvatarFileID sql.NullString `db:"profile_avatar_file_id"`
|
||||
ProfileSignature sql.NullString `db:"profile_signature"`
|
||||
ProfileGender sql.NullString `db:"profile_gender"`
|
||||
ProfileRegion sql.NullString `db:"profile_region"`
|
||||
ProfilePublicAccount sql.NullString `db:"profile_public_account"`
|
||||
}{}
|
||||
if err = rows.StructScan(&row); err != nil {
|
||||
return nil, "", err
|
||||
@@ -6350,7 +6364,7 @@ func (a *adapter) TenantFriendRequestList(id t.TenantID, uid t.Uid, direction, s
|
||||
Peer: &t.User{
|
||||
ObjHeader: t.ObjHeader{Id: peerID.String()},
|
||||
TenantID: id,
|
||||
Public: common.FromJSON(row.Public),
|
||||
Public: profilePublicFromFields(row.ProfileNickname, row.ProfileAvatarFileID, row.ProfileSignature, row.ProfileGender, row.ProfileRegion, row.ProfilePublicAccount),
|
||||
Trusted: common.FromJSON(row.Trusted),
|
||||
},
|
||||
Direction: direction,
|
||||
@@ -6699,20 +6713,20 @@ 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 p.nickname LIKE ? OR p.public_account LIKE ? OR CAST(u.public AS CHAR) LIKE ?)")
|
||||
args = append(args, like, like, like, like)
|
||||
where = append(where, "(fs.remark LIKE ? OR p.nickname LIKE ? OR p.public_account LIKE ?)")
|
||||
args = append(args, like, like, like)
|
||||
}
|
||||
if initial = strings.TrimSpace(initial); initial != "" {
|
||||
like := initial + "%"
|
||||
where = append(where, "(fs.remark LIKE ? OR p.nickname LIKE ? OR CAST(u.public AS CHAR) LIKE ?)")
|
||||
args = append(args, like, like, like)
|
||||
where = append(where, "(fs.remark LIKE ? OR p.nickname LIKE ?)")
|
||||
args = append(args, like, like)
|
||||
}
|
||||
args = append(args, limit+1)
|
||||
ctx, cancel := a.getContext()
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
rows, err := a.db.QueryxContext(ctx, `SELECT fs.*,u.public,u.trusted,
|
||||
rows, err := a.db.QueryxContext(ctx, `SELECT fs.*,u.trusted,
|
||||
p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature,
|
||||
p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account,p.updated_at AS profile_updated_at
|
||||
FROM im_friendships AS fs
|
||||
@@ -6736,7 +6750,6 @@ func (a *adapter) TenantFriendshipList(id t.TenantID, uid t.Uid, queryText, init
|
||||
Topic string
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Public any
|
||||
Trusted any
|
||||
ProfileNickname sql.NullString `db:"profile_nickname"`
|
||||
ProfileAvatarFileID sql.NullString `db:"profile_avatar_file_id"`
|
||||
@@ -6768,7 +6781,7 @@ func (a *adapter) TenantFriendshipList(id t.TenantID, uid t.Uid, queryText, init
|
||||
Peer: &t.User{
|
||||
ObjHeader: t.ObjHeader{Id: peerID.String()},
|
||||
TenantID: id,
|
||||
Public: profilePublicFromFields(common.FromJSON(row.Public), row.ProfileNickname, row.ProfileAvatarFileID, row.ProfileSignature, row.ProfileGender, row.ProfileRegion, row.ProfilePublicAccount),
|
||||
Public: profilePublicFromFields(row.ProfileNickname, row.ProfileAvatarFileID, row.ProfileSignature, row.ProfileGender, row.ProfileRegion, row.ProfilePublicAccount),
|
||||
Trusted: common.FromJSON(row.Trusted),
|
||||
},
|
||||
})
|
||||
@@ -6956,9 +6969,12 @@ 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.blocker_id,b.blocked_id,b.created_at,b.updated_at,u.public,u.trusted
|
||||
rows, err := a.db.QueryxContext(ctx, `SELECT b.blocker_id,b.blocked_id,b.created_at,b.updated_at,u.trusted,
|
||||
p.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,p.signature AS profile_signature,
|
||||
p.gender AS profile_gender,p.region AS profile_region,p.public_account AS profile_public_account
|
||||
FROM im_user_blocks AS b
|
||||
LEFT JOIN im_users AS u ON u.id=b.blocked_id
|
||||
LEFT JOIN im_user_profiles AS p ON p.user_id=b.blocked_id
|
||||
WHERE `+strings.Join(where, " AND ")+`
|
||||
ORDER BY b.blocked_id DESC LIMIT ?`, args...)
|
||||
if err != nil {
|
||||
@@ -6969,12 +6985,17 @@ func (a *adapter) TenantUserBlockList(id t.TenantID, blockerID t.Uid, cursor str
|
||||
nextCursor := ""
|
||||
for rows.Next() {
|
||||
row := struct {
|
||||
BlockerID int64 `db:"blocker_id"`
|
||||
BlockedID int64 `db:"blocked_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Public any
|
||||
Trusted any
|
||||
BlockerID int64 `db:"blocker_id"`
|
||||
BlockedID int64 `db:"blocked_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Trusted any
|
||||
ProfileNickname sql.NullString `db:"profile_nickname"`
|
||||
ProfileAvatarFileID sql.NullString `db:"profile_avatar_file_id"`
|
||||
ProfileSignature sql.NullString `db:"profile_signature"`
|
||||
ProfileGender sql.NullString `db:"profile_gender"`
|
||||
ProfileRegion sql.NullString `db:"profile_region"`
|
||||
ProfilePublicAccount sql.NullString `db:"profile_public_account"`
|
||||
}{}
|
||||
if err = rows.StructScan(&row); err != nil {
|
||||
return nil, "", err
|
||||
@@ -6995,7 +7016,7 @@ func (a *adapter) TenantUserBlockList(id t.TenantID, blockerID t.Uid, cursor str
|
||||
User: &t.User{
|
||||
ObjHeader: t.ObjHeader{Id: blockedID.String()},
|
||||
TenantID: id,
|
||||
Public: common.FromJSON(row.Public),
|
||||
Public: profilePublicFromFields(row.ProfileNickname, row.ProfileAvatarFileID, row.ProfileSignature, row.ProfileGender, row.ProfileRegion, row.ProfilePublicAccount),
|
||||
Trusted: common.FromJSON(row.Trusted),
|
||||
},
|
||||
})
|
||||
@@ -7101,8 +7122,8 @@ func (a *adapter) TenantUserSearch(id t.TenantID, viewer t.Uid, queryText, searc
|
||||
if phone, err := normalizeUserPhone(queryText); err == nil {
|
||||
phoneCandidate = phone
|
||||
}
|
||||
where = append(where, "(profile.nickname LIKE ? OR profile.public_account LIKE ? OR u.username LIKE ? OR u.phone=? OR u.phone=? OR CAST(u.public AS CHAR) LIKE ? OR u.id=?)")
|
||||
args = append(args, like, like, like, queryText, phoneCandidate, like, userIDNumericArg(queryText))
|
||||
where = append(where, "(profile.nickname LIKE ? OR profile.public_account LIKE ? OR u.username LIKE ? OR u.phone=? OR u.phone=? OR u.id=?)")
|
||||
args = append(args, like, like, like, queryText, phoneCandidate, userIDNumericArg(queryText))
|
||||
case "exact_account":
|
||||
where = append(where, "(profile.public_account=? OR u.username=? OR u.id=?)")
|
||||
args = append(args, queryText, strings.TrimPrefix(queryText, "basic:"), userIDNumericArg(queryText))
|
||||
@@ -7125,7 +7146,7 @@ func (a *adapter) TenantUserSearch(id t.TenantID, viewer t.Uid, queryText, searc
|
||||
defer cancel()
|
||||
}
|
||||
rows, err := a.db.QueryxContext(ctx, `SELECT DISTINCT ? AS tenant_id,u.id,u.username,u.createdat,u.updatedat,u.state,u.stateat,u.access,u.lastseen,u.useragent,
|
||||
COALESCE(u.phone,'') AS phone,u.public,u.trusted,
|
||||
COALESCE(u.phone,'') AS phone,u.trusted,
|
||||
profile.nickname AS profile_nickname,profile.avatar_file_id AS profile_avatar_file_id,profile.signature AS profile_signature,
|
||||
profile.gender AS profile_gender,profile.region AS profile_region,profile.public_account AS profile_public_account,profile.updated_at AS profile_updated_at
|
||||
FROM im_users AS u `+strings.Join(joins, " ")+`
|
||||
|
||||
Reference in New Issue
Block a user