gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package user
  4. import (
  5. "context"
  6. "fmt"
  7. "image/png"
  8. "io"
  9. "code.gitea.io/gitea/models/avatars"
  10. "code.gitea.io/gitea/models/db"
  11. "code.gitea.io/gitea/modules/avatar"
  12. "code.gitea.io/gitea/modules/httplib"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/setting"
  15. "code.gitea.io/gitea/modules/storage"
  16. )
  17. // CustomAvatarRelativePath returns user custom avatar relative path.
  18. func (u *User) CustomAvatarRelativePath() string {
  19. return u.Avatar
  20. }
  21. // GenerateRandomAvatar generates a random avatar for user.
  22. func GenerateRandomAvatar(ctx context.Context, u *User) error {
  23. seed := u.Email
  24. if len(seed) == 0 {
  25. seed = u.Name
  26. }
  27. img, err := avatar.RandomImage([]byte(seed))
  28. if err != nil {
  29. return fmt.Errorf("RandomImage: %w", err)
  30. }
  31. u.Avatar = avatars.HashEmail(seed)
  32. _, err = storage.Avatars.Stat(u.CustomAvatarRelativePath())
  33. if err != nil {
  34. // If unable to Stat the avatar file (usually it means non-existing), then try to save a new one
  35. // Don't share the images so that we can delete them easily
  36. if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
  37. if err := png.Encode(w, img); err != nil {
  38. log.Error("Encode: %v", err)
  39. }
  40. return nil
  41. }); err != nil {
  42. return fmt.Errorf("failed to save avatar %s: %w", u.CustomAvatarRelativePath(), err)
  43. }
  44. }
  45. if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar").Update(u); err != nil {
  46. return err
  47. }
  48. return nil
  49. }
  50. // AvatarLinkWithSize returns a link to the user's avatar with size. size <= 0 means default size
  51. func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
  52. // ghost user was deleted, Gitea actions is a bot user, 0 means the user should be a virtual user
  53. // which comes from git configure information
  54. if u.IsGhost() || u.IsGiteaActions() || u.ID <= 0 {
  55. return avatars.DefaultAvatarLink()
  56. }
  57. useLocalAvatar := false
  58. autoGenerateAvatar := false
  59. disableGravatar := setting.Config().Picture.DisableGravatar.Value(ctx)
  60. switch {
  61. case u.UseCustomAvatar:
  62. useLocalAvatar = true
  63. case disableGravatar, setting.OfflineMode:
  64. useLocalAvatar = true
  65. autoGenerateAvatar = true
  66. }
  67. if useLocalAvatar {
  68. if u.Avatar == "" && autoGenerateAvatar {
  69. if err := GenerateRandomAvatar(ctx, u); err != nil {
  70. log.Error("GenerateRandomAvatar: %v", err)
  71. }
  72. }
  73. if u.Avatar == "" {
  74. return avatars.DefaultAvatarLink()
  75. }
  76. return avatars.GenerateUserAvatarImageLink(u.Avatar, size)
  77. }
  78. return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size)
  79. }
  80. // AvatarLink returns the full avatar url with http host.
  81. // TODO: refactor it to a relative URL, but it is still used in API response at the moment
  82. func (u *User) AvatarLink(ctx context.Context) string {
  83. relLink := u.AvatarLinkWithSize(ctx, 0) // it can't be empty
  84. return httplib.MakeAbsoluteURL(ctx, relLink)
  85. }
  86. // IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data
  87. func (u *User) IsUploadAvatarChanged(data []byte) bool {
  88. if !u.UseCustomAvatar || len(u.Avatar) == 0 {
  89. return true
  90. }
  91. avatarID := avatar.HashAvatar(u.ID, data)
  92. return u.Avatar != avatarID
  93. }
  94. // ExistsWithAvatarAtStoragePath returns true if there is a user with this Avatar
  95. func ExistsWithAvatarAtStoragePath(ctx context.Context, storagePath string) (bool, error) {
  96. // See func (u *User) CustomAvatarRelativePath()
  97. // u.Avatar is used directly as the storage path - therefore we can check for existence directly using the path
  98. return db.GetEngine(ctx).Where("`avatar`=?", storagePath).Exist(new(User))
  99. }