You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

avatar.go 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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. "strings"
  11. "code.gitea.io/gitea/models/db"
  12. "code.gitea.io/gitea/modules/avatar"
  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 repository custom avatar file path.
  18. func (repo *Repository) CustomAvatarRelativePath() string {
  19. return repo.Avatar
  20. }
  21. // ExistsWithAvatarAtStoragePath returns true if there is a user with this Avatar
  22. func ExistsWithAvatarAtStoragePath(ctx context.Context, storagePath string) (bool, error) {
  23. // See func (repo *Repository) CustomAvatarRelativePath()
  24. // repo.Avatar is used directly as the storage path - therefore we can check for existence directly using the path
  25. return db.GetEngine(ctx).Where("`avatar`=?", storagePath).Exist(new(Repository))
  26. }
  27. // RelAvatarLink returns a relative link to the repository's avatar.
  28. func (repo *Repository) RelAvatarLink() string {
  29. return repo.relAvatarLink(db.DefaultContext)
  30. }
  31. // generateRandomAvatar generates a random avatar for repository.
  32. func generateRandomAvatar(ctx context.Context, repo *Repository) error {
  33. idToString := fmt.Sprintf("%d", repo.ID)
  34. seed := idToString
  35. img, err := avatar.RandomImage([]byte(seed))
  36. if err != nil {
  37. return fmt.Errorf("RandomImage: %w", err)
  38. }
  39. repo.Avatar = idToString
  40. if err := storage.SaveFrom(storage.RepoAvatars, repo.CustomAvatarRelativePath(), func(w io.Writer) error {
  41. if err := png.Encode(w, img); err != nil {
  42. log.Error("Encode: %v", err)
  43. }
  44. return err
  45. }); err != nil {
  46. return fmt.Errorf("Failed to create dir %s: %w", repo.CustomAvatarRelativePath(), err)
  47. }
  48. log.Info("New random avatar created for repository: %d", repo.ID)
  49. if _, err := db.GetEngine(ctx).ID(repo.ID).Cols("avatar").NoAutoTime().Update(repo); err != nil {
  50. return err
  51. }
  52. return nil
  53. }
  54. func (repo *Repository) relAvatarLink(ctx context.Context) string {
  55. // If no avatar - path is empty
  56. avatarPath := repo.CustomAvatarRelativePath()
  57. if len(avatarPath) == 0 {
  58. switch mode := setting.RepoAvatar.Fallback; mode {
  59. case "image":
  60. return setting.RepoAvatar.FallbackImage
  61. case "random":
  62. if err := generateRandomAvatar(ctx, repo); err != nil {
  63. log.Error("generateRandomAvatar: %v", err)
  64. }
  65. default:
  66. // default behaviour: do not display avatar
  67. return ""
  68. }
  69. }
  70. return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar)
  71. }
  72. // AvatarLink returns a link to the repository's avatar.
  73. func (repo *Repository) AvatarLink(ctx context.Context) string {
  74. link := repo.relAvatarLink(ctx)
  75. // we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL
  76. if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") {
  77. return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:]
  78. }
  79. // otherwise, return the link as it is
  80. return link
  81. }