Add HTTP /v1 MVC, TCP send path, groups with server-side member-avatar collage, object-storage upload, and friends/favorites around the architecture-v3 layout. Co-authored-by: Cursor <cursoragent@cursor.com>
62 lines
1.4 KiB
Go
62 lines
1.4 KiB
Go
package logic
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
uploadentity "spark-server/internal/module/upload/entity"
|
|
"spark-server/internal/module/user/entity"
|
|
)
|
|
|
|
const defaultAvatarMIME = "image/png"
|
|
|
|
func (s *Service) ensureDefaultAvatar(ctx context.Context, u *entity.User) {
|
|
if u == nil || strings.TrimSpace(u.Avatar) != "" {
|
|
return
|
|
}
|
|
s.stampDefaultAvatar(ctx, u)
|
|
}
|
|
|
|
func (s *Service) stampDefaultAvatar(ctx context.Context, u *entity.User) {
|
|
if u == nil || u.ID <= 0 {
|
|
return
|
|
}
|
|
fallback := entity.LetterAvatarDataURI(u.Nickname)
|
|
avatar := fallback
|
|
if key := s.putLetterPNG(ctx, u); key != "" {
|
|
avatar = key
|
|
}
|
|
prev := u.Avatar
|
|
u.Avatar = avatar
|
|
if s.repo == nil || prev == avatar {
|
|
return
|
|
}
|
|
if err := s.repo.UpdateProfile(ctx, u); err == nil {
|
|
return
|
|
}
|
|
u.Avatar = fallback
|
|
if prev != fallback {
|
|
_ = s.repo.UpdateProfile(ctx, u)
|
|
}
|
|
}
|
|
|
|
func (s *Service) putLetterPNG(ctx context.Context, u *entity.User) string {
|
|
if s == nil || s.objects == nil || s.ids == nil || u == nil || u.ID <= 0 {
|
|
return ""
|
|
}
|
|
raw, err := entity.LetterAvatarPNG(u.Nickname)
|
|
if err != nil || len(raw) == 0 {
|
|
return ""
|
|
}
|
|
objectID, err := s.ids.NextID()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
key := uploadentity.BuildObjectKey(uploadentity.PurposeAvatar, u.ID, objectID, time.Now().Format("20060102"), "png")
|
|
if err := s.objects.Put(ctx, key, raw, defaultAvatarMIME); err != nil {
|
|
return ""
|
|
}
|
|
return key
|
|
}
|