mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-12 04:27:24 +01:00
Frontend still interacts directly with the database entry name `picture.disable_gravatar` so logic needs flipped when writing, but logic to read automatically flips based on config.Invert() being called during init or INI read.
118 lines
3.6 KiB
Go
118 lines
3.6 KiB
Go
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package user
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"image/png"
|
|
"io"
|
|
|
|
"code.gitea.io/gitea/models/avatars"
|
|
"code.gitea.io/gitea/models/db"
|
|
"code.gitea.io/gitea/modules/avatar"
|
|
"code.gitea.io/gitea/modules/httplib"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
"code.gitea.io/gitea/modules/storage"
|
|
)
|
|
|
|
// CustomAvatarRelativePath returns user custom avatar relative path.
|
|
func (u *User) CustomAvatarRelativePath() string {
|
|
return u.Avatar
|
|
}
|
|
|
|
// GenerateRandomAvatar generates a random avatar for user.
|
|
func GenerateRandomAvatar(ctx context.Context, u *User) error {
|
|
seed := u.Email
|
|
if len(seed) == 0 {
|
|
seed = u.Name
|
|
}
|
|
|
|
img, err := avatar.RandomImage([]byte(seed))
|
|
if err != nil {
|
|
return fmt.Errorf("RandomImage: %w", err)
|
|
}
|
|
|
|
u.Avatar = avatars.HashEmail(seed)
|
|
|
|
_, err = storage.Avatars.Stat(u.CustomAvatarRelativePath())
|
|
if err != nil {
|
|
// If unable to Stat the avatar file (usually it means non-existing), then try to save a new one
|
|
// Don't share the images so that we can delete them easily
|
|
if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
|
|
if err := png.Encode(w, img); err != nil {
|
|
log.Error("Encode: %v", err)
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return fmt.Errorf("failed to save avatar %s: %w", u.CustomAvatarRelativePath(), err)
|
|
}
|
|
}
|
|
|
|
if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar").Update(u); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AvatarLinkWithSize returns a link to the user's avatar with size. size <= 0 means default size
|
|
func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
|
|
// ghost user was deleted, Gitea actions is a bot user, 0 means the user should be a virtual user
|
|
// which comes from git configure information
|
|
if u.IsGhost() || u.IsGiteaActions() || u.ID <= 0 {
|
|
return avatars.DefaultAvatarLink()
|
|
}
|
|
|
|
useLocalAvatar := false
|
|
autoGenerateAvatar := false
|
|
|
|
enableGravatar := setting.Config().Picture.EnableGravatar.Value(ctx)
|
|
|
|
switch {
|
|
case u.UseCustomAvatar, enableGravatar:
|
|
useLocalAvatar = true
|
|
case setting.OfflineMode:
|
|
useLocalAvatar = true
|
|
autoGenerateAvatar = true
|
|
}
|
|
|
|
if useLocalAvatar {
|
|
if u.Avatar == "" && autoGenerateAvatar {
|
|
if err := GenerateRandomAvatar(ctx, u); err != nil {
|
|
log.Error("GenerateRandomAvatar: %v", err)
|
|
}
|
|
}
|
|
if u.Avatar == "" {
|
|
return avatars.DefaultAvatarLink()
|
|
}
|
|
return avatars.GenerateUserAvatarImageLink(u.Avatar, size)
|
|
}
|
|
return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size)
|
|
}
|
|
|
|
// AvatarLink returns the full avatar url with http host.
|
|
// TODO: refactor it to a relative URL, but it is still used in API response at the moment
|
|
func (u *User) AvatarLink(ctx context.Context) string {
|
|
relLink := u.AvatarLinkWithSize(ctx, 0) // it can't be empty
|
|
return httplib.MakeAbsoluteURL(ctx, relLink)
|
|
}
|
|
|
|
// IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data
|
|
func (u *User) IsUploadAvatarChanged(data []byte) bool {
|
|
if !u.UseCustomAvatar || len(u.Avatar) == 0 {
|
|
return true
|
|
}
|
|
avatarID := avatar.HashAvatar(u.ID, data)
|
|
return u.Avatar != avatarID
|
|
}
|
|
|
|
// ExistsWithAvatarAtStoragePath returns true if there is a user with this Avatar
|
|
func ExistsWithAvatarAtStoragePath(ctx context.Context, storagePath string) (bool, error) {
|
|
// See func (u *User) CustomAvatarRelativePath()
|
|
// u.Avatar is used directly as the storage path - therefore we can check for existence directly using the path
|
|
return db.GetEngine(ctx).Where("`avatar`=?", storagePath).Exist(new(User))
|
|
}
|