gitea源码

avatar.go 2.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package repo
  4. import (
  5. "context"
  6. "fmt"
  7. "image/png"
  8. "io"
  9. "net/url"
  10. "strconv"
  11. "code.gitea.io/gitea/models/db"
  12. "code.gitea.io/gitea/modules/avatar"
  13. "code.gitea.io/gitea/modules/httplib"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/setting"
  16. "code.gitea.io/gitea/modules/storage"
  17. )
  18. // CustomAvatarRelativePath returns repository custom avatar file path.
  19. func (repo *Repository) CustomAvatarRelativePath() string {
  20. return repo.Avatar
  21. }
  22. // ExistsWithAvatarAtStoragePath returns true if there is a user with this Avatar
  23. func ExistsWithAvatarAtStoragePath(ctx context.Context, storagePath string) (bool, error) {
  24. // See func (repo *Repository) CustomAvatarRelativePath()
  25. // repo.Avatar is used directly as the storage path - therefore we can check for existence directly using the path
  26. return db.GetEngine(ctx).Where("`avatar`=?", storagePath).Exist(new(Repository))
  27. }
  28. // RelAvatarLink returns a relative link to the repository's avatar.
  29. func (repo *Repository) RelAvatarLink(ctx context.Context) string {
  30. return repo.relAvatarLink(ctx)
  31. }
  32. // generateRandomAvatar generates a random avatar for repository.
  33. func generateRandomAvatar(ctx context.Context, repo *Repository) error {
  34. idToString := strconv.FormatInt(repo.ID, 10)
  35. seed := idToString
  36. img, err := avatar.RandomImage([]byte(seed))
  37. if err != nil {
  38. return fmt.Errorf("RandomImage: %w", err)
  39. }
  40. repo.Avatar = idToString
  41. if err := storage.SaveFrom(storage.RepoAvatars, repo.CustomAvatarRelativePath(), func(w io.Writer) error {
  42. if err := png.Encode(w, img); err != nil {
  43. log.Error("Encode: %v", err)
  44. }
  45. return err
  46. }); err != nil {
  47. return fmt.Errorf("Failed to create dir %s: %w", repo.CustomAvatarRelativePath(), err)
  48. }
  49. log.Info("New random avatar created for repository: %d", repo.ID)
  50. if _, err := db.GetEngine(ctx).ID(repo.ID).Cols("avatar").NoAutoTime().Update(repo); err != nil {
  51. return err
  52. }
  53. return nil
  54. }
  55. func (repo *Repository) relAvatarLink(ctx context.Context) string {
  56. // If no avatar - path is empty
  57. avatarPath := repo.CustomAvatarRelativePath()
  58. if len(avatarPath) == 0 {
  59. switch mode := setting.RepoAvatar.Fallback; mode {
  60. case "image":
  61. return setting.RepoAvatar.FallbackImage
  62. case "random":
  63. if err := generateRandomAvatar(ctx, repo); err != nil {
  64. log.Error("generateRandomAvatar: %v", err)
  65. }
  66. default:
  67. // default behaviour: do not display avatar
  68. return ""
  69. }
  70. }
  71. return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar)
  72. }
  73. // AvatarLink returns the full avatar url with http host or the empty string if the repo doesn't have an avatar.
  74. //
  75. // TODO: refactor it to a relative URL, but it is still used in API response at the moment
  76. func (repo *Repository) AvatarLink(ctx context.Context) string {
  77. relLink := repo.relAvatarLink(ctx)
  78. if relLink != "" {
  79. return httplib.MakeAbsoluteURL(ctx, relLink)
  80. }
  81. return ""
  82. }