2020-10-14 16:07:51 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"crypto/md5"
"fmt"
"image/png"
"io"
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
"code.gitea.io/gitea/models/avatars"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2020-10-14 16:07:51 +03:00
"code.gitea.io/gitea/modules/avatar"
"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 ( u * User ) GenerateRandomAvatar ( ) error {
2021-09-23 18:45:36 +03:00
return u . generateRandomAvatar ( db . GetEngine ( db . DefaultContext ) )
2020-10-14 16:07:51 +03:00
}
2021-09-19 14:49:59 +03:00
func ( u * User ) generateRandomAvatar ( e db . Engine ) error {
2020-10-14 16:07:51 +03:00
seed := u . Email
if len ( seed ) == 0 {
seed = u . Name
}
img , err := avatar . RandomImage ( [ ] byte ( seed ) )
if err != nil {
return fmt . Errorf ( "RandomImage: %v" , err )
}
2020-10-23 20:55:10 +03:00
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
u . Avatar = avatars . HashEmail ( seed )
2020-10-14 16:07:51 +03:00
2021-01-02 21:01:09 +03:00
// Don't share the images so that we can delete them easily
2020-10-14 16:07:51 +03:00
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 err
} ) ; err != nil {
return fmt . Errorf ( "Failed to create dir %s: %v" , u . CustomAvatarRelativePath ( ) , err )
}
if _ , err := e . ID ( u . ID ) . Cols ( "avatar" ) . Update ( u ) ; err != nil {
return err
}
log . Info ( "New random avatar created: %d" , u . ID )
return nil
}
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
// AvatarLinkWithSize returns a link to the user's avatar with size. size <= 0 means default size
func ( u * User ) AvatarLinkWithSize ( size int ) string {
2020-10-14 16:07:51 +03:00
if u . ID == - 1 {
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
// ghost user
return avatars . DefaultAvatarLink ( )
2020-10-14 16:07:51 +03:00
}
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
useLocalAvatar := false
autoGenerateAvatar := false
2020-10-14 16:07:51 +03:00
switch {
case u . UseCustomAvatar :
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
useLocalAvatar = true
2020-10-14 16:07:51 +03:00
case setting . DisableGravatar , setting . OfflineMode :
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
useLocalAvatar = true
autoGenerateAvatar = true
}
if useLocalAvatar {
if u . Avatar == "" && autoGenerateAvatar {
2020-10-14 16:07:51 +03:00
if err := u . GenerateRandomAvatar ( ) ; err != nil {
log . Error ( "GenerateRandomAvatar: %v" , err )
}
}
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
if u . Avatar == "" {
return avatars . DefaultAvatarLink ( )
2021-04-17 01:22:25 +03:00
}
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
return avatars . GenerateUserAvatarImageLink ( u . Avatar , size )
2020-10-14 16:07:51 +03:00
}
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
return avatars . GenerateEmailAvatarFastLink ( u . AvatarEmail , size )
2020-10-14 16:07:51 +03:00
}
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
// AvatarLink returns a avatar link with default size
2020-10-14 16:07:51 +03:00
func ( u * User ) AvatarLink ( ) string {
Avatar refactor, move avatar code from `models` to `models.avatars`, remove duplicated code (#17123)
Why this refactor
The goal is to move most files from `models` package to `models.xxx` package. Many models depend on avatar model, so just move this first.
And the existing logic is not clear, there are too many function like `AvatarLink`, `RelAvatarLink`, `SizedRelAvatarLink`, `SizedAvatarLink`, `MakeFinalAvatarURL`, `HashedAvatarLink`, etc. This refactor make everything clear:
* user.AvatarLink()
* user.AvatarLinkWithSize(size)
* avatars.GenerateEmailAvatarFastLink(email, size)
* avatars.GenerateEmailAvatarFinalLink(email, size)
And many duplicated code are deleted in route handler, the handler and the model share the same avatar logic now.
2021-10-06 02:25:46 +03:00
return u . AvatarLinkWithSize ( 0 )
2020-10-14 16:07:51 +03:00
}
// UploadAvatar saves custom avatar for user.
// FIXME: split uploads to different subdirs in case we have massive users.
func ( u * User ) UploadAvatar ( data [ ] byte ) error {
m , err := avatar . Prepare ( data )
if err != nil {
return err
}
2021-09-23 18:45:36 +03:00
sess := db . NewSession ( db . DefaultContext )
2020-10-14 16:07:51 +03:00
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
u . UseCustomAvatar = true
// Different users can upload same image as avatar
// If we prefix it with u.ID, it will be separated
// Otherwise, if any of the users delete his avatar
// Other users will lose their avatars too.
u . Avatar = fmt . Sprintf ( "%x" , md5 . Sum ( [ ] byte ( fmt . Sprintf ( "%d-%x" , u . ID , md5 . Sum ( data ) ) ) ) )
2021-01-02 21:01:09 +03:00
if err = updateUserCols ( sess , u , "use_custom_avatar" , "avatar" ) ; err != nil {
2020-10-14 16:07:51 +03:00
return fmt . Errorf ( "updateUser: %v" , err )
}
if err := storage . SaveFrom ( storage . Avatars , u . CustomAvatarRelativePath ( ) , func ( w io . Writer ) error {
if err := png . Encode ( w , * m ) ; err != nil {
log . Error ( "Encode: %v" , err )
}
return err
} ) ; err != nil {
return fmt . Errorf ( "Failed to create dir %s: %v" , u . CustomAvatarRelativePath ( ) , err )
}
return sess . Commit ( )
}
2021-09-27 05:39:36 +03:00
// 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 := fmt . Sprintf ( "%x" , md5 . Sum ( [ ] byte ( fmt . Sprintf ( "%d-%x" , u . ID , md5 . Sum ( data ) ) ) ) )
return u . Avatar != avatarID
}
2020-10-14 16:07:51 +03:00
// DeleteAvatar deletes the user's custom avatar.
func ( u * User ) DeleteAvatar ( ) error {
aPath := u . CustomAvatarRelativePath ( )
log . Trace ( "DeleteAvatar[%d]: %s" , u . ID , aPath )
if len ( u . Avatar ) > 0 {
if err := storage . Avatars . Delete ( aPath ) ; err != nil {
return fmt . Errorf ( "Failed to remove %s: %v" , aPath , err )
}
}
u . UseCustomAvatar = false
u . Avatar = ""
2021-09-23 18:45:36 +03:00
if _ , err := db . GetEngine ( db . DefaultContext ) . ID ( u . ID ) . Cols ( "avatar, use_custom_avatar" ) . Update ( u ) ; err != nil {
2020-10-14 16:07:51 +03:00
return fmt . Errorf ( "UpdateUser: %v" , err )
}
return nil
}