Files
im_server/server/default_avatar.go
T

126 lines
3.0 KiB
Go

package main
import (
"encoding/json"
"hash/fnv"
"strings"
"github.com/tinode/chat/server/store"
"github.com/tinode/chat/server/store/types"
)
const (
imAssetsConfigGroup = "im_assets"
imDefaultMaleAvatarURLsConfig = "default_user_avatar_male_urls"
imDefaultFemaleAvatarURLsConfig = "default_user_avatar_female_urls"
)
func applyDefaultUserAvatar(data map[string]any, userID, gender string) {
if data == nil {
return
}
if strings.TrimSpace(stringFromAny(data["avatar_file_id"])) == "" {
avatarURL := defaultUserAvatarURL(userID, gender)
if avatarURL == "" {
return
}
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 {
if store.ThirdPartyConfig == nil {
return ""
}
values, err := store.ThirdPartyConfig.Get(imAssetsConfigGroup, imDefaultMaleAvatarURLsConfig, imDefaultFemaleAvatarURLsConfig)
if err != nil {
return ""
}
key := imDefaultMaleAvatarURLsConfig
if strings.EqualFold(strings.TrimSpace(gender), "female") {
key = imDefaultFemaleAvatarURLsConfig
}
urls := parseDefaultAvatarURLs(values[key])
if len(urls) == 0 && key == imDefaultFemaleAvatarURLsConfig {
urls = parseDefaultAvatarURLs(values[imDefaultMaleAvatarURLsConfig])
}
if len(urls) == 0 {
return ""
}
return urls[defaultAvatarIndex(userID, len(urls))]
}
func parseDefaultAvatarURLs(raw string) []string {
var urls []string
if err := json.Unmarshal([]byte(strings.TrimSpace(raw)), &urls); err != nil {
return nil
}
out := urls[:0]
for _, url := range urls {
if url = strings.TrimSpace(url); url != "" {
out = append(out, url)
}
}
return out
}
func defaultAvatarIndex(userID string, count int) int {
if count <= 1 {
return 0
}
uid := types.ParseUserId(strings.TrimSpace(userID))
if uid.IsZero() {
uid = types.ParseUid(strings.TrimSpace(userID))
}
if !uid.IsZero() {
return int(uint64(uid) % uint64(count))
}
h := fnv.New32a()
_, _ = h.Write([]byte(userID))
return int(h.Sum32() % uint32(count))
}