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

icon.go 2.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package badge
  2. import (
  3. "bytes"
  4. "code.gitea.io/gitea/models"
  5. "code.gitea.io/gitea/modules/base"
  6. "code.gitea.io/gitea/modules/setting"
  7. "crypto/md5"
  8. "errors"
  9. "fmt"
  10. "image"
  11. "image/png"
  12. "io/ioutil"
  13. "mime/multipart"
  14. "os"
  15. )
  16. type IconUploader struct {
  17. Config IconUploadConfig
  18. }
  19. type IconUploadForm struct {
  20. Icon *multipart.FileHeader
  21. }
  22. type IconUploadConfig struct {
  23. FileMaxSize int64
  24. FileMaxWidth int
  25. FileMaxHeight int
  26. }
  27. func NewIconUploader(config IconUploadConfig) IconUploader {
  28. return IconUploader{Config: config}
  29. }
  30. func (u IconUploader) Upload(form IconUploadForm, user *models.User) (string, error) {
  31. if form.Icon == nil || form.Icon.Filename == "" {
  32. return "", errors.New("File or fileName is empty")
  33. }
  34. fr, err := form.Icon.Open()
  35. if err != nil {
  36. return "", fmt.Errorf("Icon.Open: %v", err)
  37. }
  38. defer fr.Close()
  39. if form.Icon.Size > u.Config.FileMaxSize {
  40. return "", errors.New("File is too large")
  41. }
  42. data, err := ioutil.ReadAll(fr)
  43. if err != nil {
  44. return "", fmt.Errorf("ioutil.ReadAll: %v", err)
  45. }
  46. if !base.IsImageFile(data) {
  47. return "", errors.New("File is not a image")
  48. }
  49. iconName, err := u.uploadIcon(data, user.ID)
  50. if err != nil {
  51. return "", fmt.Errorf("uploadIcon: %v", err)
  52. }
  53. return iconName, nil
  54. }
  55. func (u IconUploader) uploadIcon(data []byte, userId int64) (string, error) {
  56. m, err := u.prepare(data)
  57. if err != nil {
  58. return "", err
  59. }
  60. iconName := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", userId, md5.Sum(data)))))
  61. if err := os.MkdirAll(setting.IconUploadPath, os.ModePerm); err != nil {
  62. return "", fmt.Errorf("uploadIcon. Failed to create dir %s: %v", setting.AvatarUploadPath, err)
  63. }
  64. fw, err := os.Create(models.GetCustomIconByHash(iconName))
  65. if err != nil {
  66. return "", fmt.Errorf("Create: %v", err)
  67. }
  68. defer fw.Close()
  69. if err = png.Encode(fw, *m); err != nil {
  70. return "", fmt.Errorf("Encode: %v", err)
  71. }
  72. return iconName, nil
  73. }
  74. func (u IconUploader) prepare(data []byte) (*image.Image, error) {
  75. imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data))
  76. if err != nil {
  77. return nil, fmt.Errorf("DecodeConfig: %v", err)
  78. }
  79. if imgCfg.Width > u.Config.FileMaxWidth {
  80. return nil, fmt.Errorf("Image width is too large: %d > %d", imgCfg.Width, setting.AvatarMaxWidth)
  81. }
  82. if imgCfg.Height > u.Config.FileMaxHeight {
  83. return nil, fmt.Errorf("Image height is too large: %d > %d", imgCfg.Height, setting.AvatarMaxHeight)
  84. }
  85. img, _, err := image.Decode(bytes.NewReader(data))
  86. if err != nil {
  87. return nil, fmt.Errorf("Decode: %v", err)
  88. }
  89. return &img, nil
  90. }