fix: align member meta default avatars
This commit is contained in:
@@ -16,12 +16,60 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func applyDefaultUserAvatar(data map[string]any, userID, gender string) {
|
func applyDefaultUserAvatar(data map[string]any, userID, gender string) {
|
||||||
if data == nil || strings.TrimSpace(stringFromAny(data["avatar_file_id"])) != "" {
|
if data == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if avatarURL := defaultUserAvatarURL(userID, gender); avatarURL != "" {
|
if strings.TrimSpace(stringFromAny(data["avatar_file_id"])) == "" {
|
||||||
|
avatarURL := defaultUserAvatarURL(userID, gender)
|
||||||
|
if avatarURL == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
data["avatar_file_id"] = avatarURL
|
data["avatar_file_id"] = avatarURL
|
||||||
}
|
}
|
||||||
|
applyAvatarURL(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyAvatarURL(data map[string]any) {
|
||||||
|
if data == nil || strings.TrimSpace(stringFromAny(data["avatar_url"])) != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
avatar := strings.TrimSpace(stringFromAny(data["avatar_file_id"]))
|
||||||
|
if isAvatarURLValue(avatar) {
|
||||||
|
data["avatar_url"] = avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func publicWithDefaultUserAvatar(public any, userID string) any {
|
||||||
|
data := publicToMap(public)
|
||||||
|
gender := stringFromAny(data["gender"])
|
||||||
|
applyDefaultUserAvatar(data, userID, gender)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func publicToMap(public any) map[string]any {
|
||||||
|
switch value := public.(type) {
|
||||||
|
case nil:
|
||||||
|
return map[string]any{}
|
||||||
|
case map[string]any:
|
||||||
|
out := make(map[string]any, len(value)+1)
|
||||||
|
for k, v := range value {
|
||||||
|
out[k] = v
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
case types.KVMap:
|
||||||
|
out := make(map[string]any, len(value)+1)
|
||||||
|
for k, v := range value {
|
||||||
|
out[k] = v
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
default:
|
||||||
|
return map[string]any{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAvatarURLValue(value string) bool {
|
||||||
|
return strings.HasPrefix(value, "http://") || strings.HasPrefix(value, "https://") ||
|
||||||
|
strings.HasPrefix(value, "data:") || strings.HasPrefix(value, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultUserAvatarURL(userID, gender string) string {
|
func defaultUserAvatarURL(userID, gender string) string {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ func (s defaultAvatarConfigStore) Get(_ string, keys ...string) (map[string]stri
|
|||||||
func TestUserSummaryPayloadAppliesDefaultAvatarByGenderAndUserID(t *testing.T) {
|
func TestUserSummaryPayloadAppliesDefaultAvatarByGenderAndUserID(t *testing.T) {
|
||||||
oldConfig := store.ThirdPartyConfig
|
oldConfig := store.ThirdPartyConfig
|
||||||
store.ThirdPartyConfig = defaultAvatarConfigStore{
|
store.ThirdPartyConfig = defaultAvatarConfigStore{
|
||||||
imDefaultMaleAvatarURLsConfig: `["m0","m1","m2","m3","m4"]`,
|
imDefaultMaleAvatarURLsConfig: `["https://oss.example.com/m0.png","https://oss.example.com/m1.png","https://oss.example.com/m2.png","https://oss.example.com/m3.png","https://oss.example.com/m4.png"]`,
|
||||||
imDefaultFemaleAvatarURLsConfig: `["f0","f1","f2","f3","f4"]`,
|
imDefaultFemaleAvatarURLsConfig: `["https://oss.example.com/f0.png","https://oss.example.com/f1.png","https://oss.example.com/f2.png","https://oss.example.com/f3.png","https://oss.example.com/f4.png"]`,
|
||||||
}
|
}
|
||||||
defer func() { store.ThirdPartyConfig = oldConfig }()
|
defer func() { store.ThirdPartyConfig = oldConfig }()
|
||||||
|
|
||||||
@@ -36,10 +36,13 @@ func TestUserSummaryPayloadAppliesDefaultAvatarByGenderAndUserID(t *testing.T) {
|
|||||||
if gender == "female" {
|
if gender == "female" {
|
||||||
wantPrefix = "f"
|
wantPrefix = "f"
|
||||||
}
|
}
|
||||||
want := fmt.Sprintf("%s%d", wantPrefix, uint64(uid)%5)
|
want := fmt.Sprintf("https://oss.example.com/%s%d.png", wantPrefix, uint64(uid)%5)
|
||||||
if payload["avatar_file_id"] != want {
|
if payload["avatar_file_id"] != want {
|
||||||
t.Fatalf("gender=%s avatar=%v want %s", gender, payload["avatar_file_id"], want)
|
t.Fatalf("gender=%s avatar=%v want %s", gender, payload["avatar_file_id"], want)
|
||||||
}
|
}
|
||||||
|
if payload["avatar_url"] != want {
|
||||||
|
t.Fatalf("gender=%s avatar_url=%v want %s", gender, payload["avatar_url"], want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,4 +60,48 @@ func TestUserSummaryPayloadKeepsUploadedAvatar(t *testing.T) {
|
|||||||
if payload["avatar_file_id"] != "uploaded.png" {
|
if payload["avatar_file_id"] != "uploaded.png" {
|
||||||
t.Fatalf("avatar=%v", payload["avatar_file_id"])
|
t.Fatalf("avatar=%v", payload["avatar_file_id"])
|
||||||
}
|
}
|
||||||
|
if _, ok := payload["avatar_url"]; ok {
|
||||||
|
t.Fatalf("non-url uploaded avatar must not be exposed as avatar_url: %#v", payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPublicWithDefaultUserAvatarMatchesHTTPSummary(t *testing.T) {
|
||||||
|
oldConfig := store.ThirdPartyConfig
|
||||||
|
store.ThirdPartyConfig = defaultAvatarConfigStore{
|
||||||
|
imDefaultMaleAvatarURLsConfig: `["https://oss.example.com/m0.png","https://oss.example.com/m1.png"]`,
|
||||||
|
imDefaultFemaleAvatarURLsConfig: `["https://oss.example.com/f0.png","https://oss.example.com/f1.png"]`,
|
||||||
|
}
|
||||||
|
defer func() { store.ThirdPartyConfig = oldConfig }()
|
||||||
|
|
||||||
|
uid := types.Uid(11)
|
||||||
|
public := publicWithDefaultUserAvatar(map[string]any{"display_name": "Alice", "gender": "female"}, uid.UserId()).(map[string]any)
|
||||||
|
want := "https://oss.example.com/f1.png"
|
||||||
|
if public["avatar_file_id"] != want || public["avatar_url"] != want {
|
||||||
|
t.Fatalf("default avatar not applied to protocol public: %#v", public)
|
||||||
|
}
|
||||||
|
|
||||||
|
summary := userSummaryPayload(&types.User{
|
||||||
|
ObjHeader: types.ObjHeader{Id: uid.String()},
|
||||||
|
Public: map[string]any{"display_name": "Alice", "gender": "female"},
|
||||||
|
}, "")
|
||||||
|
if summary["avatar_file_id"] != public["avatar_file_id"] || summary["avatar_url"] != public["avatar_url"] {
|
||||||
|
t.Fatalf("protocol public and HTTP summary diverged: public=%#v summary=%#v", public, summary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPublicWithDefaultUserAvatarKeepsExistingAvatarURL(t *testing.T) {
|
||||||
|
oldConfig := store.ThirdPartyConfig
|
||||||
|
store.ThirdPartyConfig = defaultAvatarConfigStore{
|
||||||
|
imDefaultMaleAvatarURLsConfig: `["https://oss.example.com/default.png"]`,
|
||||||
|
}
|
||||||
|
defer func() { store.ThirdPartyConfig = oldConfig }()
|
||||||
|
|
||||||
|
public := publicWithDefaultUserAvatar(types.KVMap{
|
||||||
|
"display_name": "Bob",
|
||||||
|
"avatar_file_id": "file_1",
|
||||||
|
"avatar_url": "https://oss.example.com/file_1.png",
|
||||||
|
}, types.Uid(20).UserId()).(map[string]any)
|
||||||
|
if public["avatar_file_id"] != "file_1" || public["avatar_url"] != "https://oss.example.com/file_1.png" {
|
||||||
|
t.Fatalf("existing avatar should be kept: %#v", public)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9143,6 +9143,9 @@ func copyUserPublicSummary(data map[string]any, public map[string]any) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if value, ok := public["avatar_url"]; ok && strings.TrimSpace(fmt.Sprint(value)) != "" {
|
||||||
|
data["avatar_url"] = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func displayInitial(value any) string {
|
func displayInitial(value any) string {
|
||||||
|
|||||||
+5
-1
@@ -3374,7 +3374,11 @@ func (t *Topic) replyGetSub(sess *Session, asUid types.Uid, authLevel auth.Level
|
|||||||
// Returning public and private only if they have changed since ifModified
|
// Returning public and private only if they have changed since ifModified
|
||||||
if sendPubPriv {
|
if sendPubPriv {
|
||||||
// 'sub' has nil 'public'/'trusted' in P2P topics which is OK.
|
// 'sub' has nil 'public'/'trusted' in P2P topics which is OK.
|
||||||
mts.Public = sub.GetPublic()
|
if t.cat == types.TopicCatGrp {
|
||||||
|
mts.Public = publicWithDefaultUserAvatar(sub.GetPublic(), uid.UserId())
|
||||||
|
} else {
|
||||||
|
mts.Public = sub.GetPublic()
|
||||||
|
}
|
||||||
mts.Trusted = sub.GetTrusted()
|
mts.Trusted = sub.GetTrusted()
|
||||||
// Reporting 'private' only if it's user's own subscription.
|
// Reporting 'private' only if it's user's own subscription.
|
||||||
if uid == asUid {
|
if uid == asUid {
|
||||||
|
|||||||
Reference in New Issue
Block a user