feat: include avatar url in member public meta
This commit is contained in:
@@ -2630,10 +2630,11 @@ func (a *adapter) UsersForTopic(topic string, keepDeleted bool, opts *t.QueryOpt
|
||||
// Fetch all subscribed users. The number of users is not large.
|
||||
q := `SELECT s.createdat,s.updatedat,s.deletedat,s.userid,s.topic,s.delid,s.recvseqid,
|
||||
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.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,pu.location AS profile_avatar_url,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.userid=u.id
|
||||
LEFT JOIN im_user_profiles AS p ON p.user_id=s.userid
|
||||
LEFT JOIN im_public_uploads AS pu ON pu.file_id=p.avatar_file_id
|
||||
WHERE s.topic=?`
|
||||
args := []any{topic}
|
||||
if !keepDeleted {
|
||||
@@ -2686,21 +2687,21 @@ func (a *adapter) UsersForTopic(topic string, keepDeleted bool, opts *t.QueryOpt
|
||||
var lastSeen sql.NullTime
|
||||
var userAgent string
|
||||
var trusted any
|
||||
var profileNickname, profileAvatarFileID, profileSignature, profileGender, profileRegion, profilePublicAccount sql.NullString
|
||||
var profileNickname, profileAvatarFileID, profileAvatarURL, profileSignature, profileGender, profileRegion, profilePublicAccount sql.NullString
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(
|
||||
&sub.CreatedAt, &sub.UpdatedAt, &sub.DeletedAt,
|
||||
&sub.User, &sub.Topic, &sub.DelId, &sub.RecvSeqId,
|
||||
&sub.ReadSeqId, &sub.ModeWant, &sub.ModeGiven,
|
||||
&trusted, &lastSeen, &userAgent, &sub.Private,
|
||||
&profileNickname, &profileAvatarFileID, &profileSignature,
|
||||
&profileNickname, &profileAvatarFileID, &profileAvatarURL, &profileSignature,
|
||||
&profileGender, &profileRegion, &profilePublicAccount); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
sub.User = common.EncodeUidString(sub.User).String()
|
||||
sub.Private = common.FromJSON(sub.Private)
|
||||
sub.SetPublic(profilePublicFromFields(profileNickname, profileAvatarFileID, profileSignature, profileGender, profileRegion, profilePublicAccount))
|
||||
sub.SetPublic(profilePublicFromFieldsWithAvatarURL(profileNickname, profileAvatarFileID, profileAvatarURL, profileSignature, profileGender, profileRegion, profilePublicAccount))
|
||||
sub.SetTrusted(common.FromJSON(trusted))
|
||||
sub.SetLastSeenAndUA(&lastSeen.Time, userAgent)
|
||||
subs = append(subs, sub)
|
||||
|
||||
@@ -62,6 +62,7 @@ type profileUserRow struct {
|
||||
Trusted any `db:"trusted"`
|
||||
ProfileNickname sql.NullString `db:"profile_nickname"`
|
||||
ProfileAvatarFileID sql.NullString `db:"profile_avatar_file_id"`
|
||||
ProfileAvatarURL sql.NullString `db:"profile_avatar_url"`
|
||||
ProfileSignature sql.NullString `db:"profile_signature"`
|
||||
ProfileGender sql.NullString `db:"profile_gender"`
|
||||
ProfileRegion sql.NullString `db:"profile_region"`
|
||||
@@ -85,7 +86,7 @@ func (row profileUserRow) lastSeen() *time.Time {
|
||||
}
|
||||
|
||||
func (row profileUserRow) profilePublic() any {
|
||||
return profilePublicFromFields(row.ProfileNickname, row.ProfileAvatarFileID, row.ProfileSignature, row.ProfileGender, row.ProfileRegion, row.ProfilePublicAccount)
|
||||
return profilePublicFromFieldsWithAvatarURL(row.ProfileNickname, row.ProfileAvatarFileID, row.ProfileAvatarURL, row.ProfileSignature, row.ProfileGender, row.ProfileRegion, row.ProfilePublicAccount)
|
||||
}
|
||||
|
||||
func profileUserFromRow(row profileUserRow) t.User {
|
||||
@@ -111,6 +112,10 @@ func profileUserFromRow(row profileUserRow) t.User {
|
||||
}
|
||||
|
||||
func profilePublicFromFields(nickname, avatarFileID, signature, gender, region, publicAccount sql.NullString) any {
|
||||
return profilePublicFromFieldsWithAvatarURL(nickname, avatarFileID, sql.NullString{}, signature, gender, region, publicAccount)
|
||||
}
|
||||
|
||||
func profilePublicFromFieldsWithAvatarURL(nickname, avatarFileID, avatarURL, signature, gender, region, publicAccount sql.NullString) any {
|
||||
public := map[string]any{}
|
||||
if nickname.Valid {
|
||||
value := strings.TrimSpace(nickname.String)
|
||||
@@ -124,6 +129,9 @@ func profilePublicFromFields(nickname, avatarFileID, signature, gender, region,
|
||||
value := strings.TrimSpace(avatarFileID.String)
|
||||
if value != "" {
|
||||
public["avatar_file_id"] = value
|
||||
if url := profileAvatarURL(value, avatarURL); url != "" {
|
||||
public["avatar_url"] = url
|
||||
}
|
||||
}
|
||||
}
|
||||
if signature.Valid {
|
||||
@@ -186,6 +194,20 @@ func sanitizeUserUpdate(update map[string]any) map[string]any {
|
||||
return update
|
||||
}
|
||||
|
||||
func profileAvatarURL(avatarFileID string, avatarURL sql.NullString) string {
|
||||
if avatarURL.Valid {
|
||||
if value := strings.TrimSpace(avatarURL.String); value != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
value := strings.TrimSpace(avatarFileID)
|
||||
if strings.HasPrefix(value, "http://") || strings.HasPrefix(value, "https://") ||
|
||||
strings.HasPrefix(value, "data:") || strings.HasPrefix(value, "/") {
|
||||
return value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func profileSeedFromPublic(public any) (nickname, avatarFileID string) {
|
||||
values := publicMap(public)
|
||||
for _, key := range []string{"display_name", "nickname", "fn", "name"} {
|
||||
@@ -1302,10 +1324,11 @@ 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.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.nickname AS profile_nickname,p.avatar_file_id AS profile_avatar_file_id,pu.location AS profile_avatar_url,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
|
||||
LEFT JOIN im_user_profiles AS p ON p.tenant_id=s.tenant_id AND p.user_id=s.userid
|
||||
LEFT JOIN im_public_uploads AS pu ON pu.file_id=p.avatar_file_id
|
||||
WHERE s.tenant_id=? AND s.topic=?`
|
||||
q = tenantShardSQL(id, q)
|
||||
args := []any{id, topic}
|
||||
@@ -1347,17 +1370,17 @@ func (a *adapter) TenantUsersForTopic(id t.TenantID, topic string, keepDeleted b
|
||||
var sub t.Subscription
|
||||
var lastSeen sql.NullTime
|
||||
var trusted any
|
||||
var profileNickname, profileAvatarFileID, profileSignature, profileGender, profileRegion, profilePublicAccount sql.NullString
|
||||
var profileNickname, profileAvatarFileID, profileAvatarURL, 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,
|
||||
&trusted, &lastSeen, &userAgent, &sub.Private,
|
||||
&profileNickname, &profileAvatarFileID, &profileSignature,
|
||||
&profileNickname, &profileAvatarFileID, &profileAvatarURL, &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(profileNickname, profileAvatarFileID, profileSignature, profileGender, profileRegion, profilePublicAccount))
|
||||
sub.SetPublic(profilePublicFromFieldsWithAvatarURL(profileNickname, profileAvatarFileID, profileAvatarURL, profileSignature, profileGender, profileRegion, profilePublicAccount))
|
||||
sub.SetTrusted(common.FromJSON(trusted))
|
||||
sub.SetLastSeenAndUA(&lastSeen.Time, userAgent)
|
||||
subs = append(subs, sub)
|
||||
|
||||
@@ -42,9 +42,22 @@ func TestProfilePublicFromFields(t *testing.T) {
|
||||
t.Fatalf("profile public not overlaid: %#v", public)
|
||||
}
|
||||
|
||||
public = profilePublicFromFieldsWithAvatarURL(sql.NullString{}, sql.NullString{String: "file_avatar_1", Valid: true},
|
||||
sql.NullString{String: "https://cdn.example.com/avatar.png", Valid: true}, sql.NullString{}, sql.NullString{},
|
||||
sql.NullString{}, sql.NullString{}).(map[string]any)
|
||||
if public["avatar_file_id"] != "file_avatar_1" || public["avatar_url"] != "https://cdn.example.com/avatar.png" {
|
||||
t.Fatalf("avatar url not overlaid: %#v", public)
|
||||
}
|
||||
|
||||
public = profilePublicFromFields(sql.NullString{}, sql.NullString{String: "https://cdn.example.com/default.png", Valid: true},
|
||||
sql.NullString{}, sql.NullString{}, sql.NullString{}, sql.NullString{}).(map[string]any)
|
||||
if public["avatar_file_id"] != "https://cdn.example.com/default.png" || public["avatar_url"] != "https://cdn.example.com/default.png" {
|
||||
t.Fatalf("absolute avatar value should be exposed as avatar_url: %#v", public)
|
||||
}
|
||||
|
||||
public = profilePublicFromFields(sql.NullString{Valid: true}, sql.NullString{Valid: true}, sql.NullString{Valid: true},
|
||||
sql.NullString{Valid: true}, sql.NullString{Valid: true}, sql.NullString{Valid: true}).(map[string]any)
|
||||
for _, key := range []string{"fn", "name", "nickname", "display_name", "avatar_file_id", "photo", "avatar", "signature", "gender", "region", "public_account"} {
|
||||
for _, key := range []string{"fn", "name", "nickname", "display_name", "avatar_file_id", "avatar_url", "photo", "avatar", "signature", "gender", "region", "public_account"} {
|
||||
if _, ok := public[key]; ok {
|
||||
t.Fatalf("legacy profile field %s should not be read from im_users.public: %#v", key, public)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user