feat: export AvatarURL for the display picture at any size
- AvatarURL returns the avatar thumbnail, the file path when the thumbnail fails, or the gravatar URL, the rule of the user payload - applyAvatar takes avatar_url from it; the payload is unchanged
This commit is contained in:
65
classes/avatar.go
Normal file
65
classes/avatar.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package classes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.golem15.com/golem15/sm-user-plugin/models"
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/lagoon/attach"
|
||||
"gocloud.dev/blob"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// AvatarURL returns the display picture URL of user at size pixels, the
|
||||
// rule the user API payload follows: the thumbnail (size by size, mode
|
||||
// auto) of the user's avatar attachment when there is one and a file
|
||||
// bucket is published, the attachment's file path when the thumbnail
|
||||
// fails (logged), and otherwise the gravatar URL
|
||||
// //www.gravatar.com/avatar/{md5 of the email}?s={size}&d=mm. The URL may
|
||||
// be protocol-relative or relative; a caller that needs an absolute URL
|
||||
// resolves it. Only a failing database lookup is an error.
|
||||
func AvatarURL(ctx context.Context, app *backpack.App, user *models.User, size int) (string, error) {
|
||||
if user == nil {
|
||||
return "", errors.New("golem15.user: avatar needs a user")
|
||||
}
|
||||
fallback := gravatar(user.Email, size)
|
||||
if app == nil || user.ID == 0 {
|
||||
return fallback, nil
|
||||
}
|
||||
gdb, ok := app.Lookup[*gorm.DB]()
|
||||
if !ok || gdb == nil {
|
||||
return fallback, nil
|
||||
}
|
||||
var f attach.File
|
||||
err := gdb.WithContext(ctx).
|
||||
Where("attachment_type = ? AND attachment_id = ? AND field = ?", user.MorphName(), strconv.FormatUint(uint64(user.ID), 10), models.AvatarField).
|
||||
Take(&f).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fallback, nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bucket, ok := app.Lookup[*blob.Bucket]()
|
||||
if !ok || bucket == nil {
|
||||
return fallback, nil
|
||||
}
|
||||
url, err := f.Thumb(ctx, bucket, size, size, "auto")
|
||||
if err != nil {
|
||||
slog.Default().Error("golem15.user: avatar thumb", "err", err)
|
||||
return "/" + attach.BlobKey(f.DiskName), nil
|
||||
}
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// gravatar is the gravatar URL of an email at size pixels.
|
||||
func gravatar(email string, size int) string {
|
||||
sum := md5.Sum([]byte(strings.ToLower(strings.TrimSpace(email))))
|
||||
return fmt.Sprintf("//www.gravatar.com/avatar/%x?s=%d&d=mm", sum, size)
|
||||
}
|
||||
Reference in New Issue
Block a user