package image import ( "errors" "io" "mime/multipart" "os" "strconv" "clickandjoin.app/storageserver/modules/config" "clickandjoin.app/storageserver/modules/utils" "github.com/google/uuid" "github.com/h2non/bimg" "github.com/sirupsen/logrus" ) // is specified in the form data of the frontend const FormFileKey = "file" const MaxAvatarSize = 2 * 1024 * 1024 // 2 MB // filename len = 36 + dot . 1 + longestFileType 4 // example: cf75ace7-da4c-434d-bf7d-0bdbcea5c57d.webp const MaxFileNameLen = 41 var validFileTypes = []string{"jpeg", "jpg", "png", "webp"} // represents the query parameter size for the dynamic image resolution // example ?size=1 -> 64x64 var ImageSizes = []int{32, 64, 150, 256, 512, 1024} const DefaultImageSize = 0 func FileTypeVerification(fileType string) bool { for _, validFileType := range validFileTypes { if fileType == "image/"+validFileType { return true } } return false } func createUserFolder(userId string) error { path := config.Cfg.StoragePath + userId if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { err = os.Mkdir(utils.GetUserStoragePath(userId), os.ModePerm) if err != nil && !errors.Is(err, os.ErrExist) { logrus.Errorln("Failed to create user folder, err:", err) return err } } return nil } func SaveImage(fileHeader *multipart.FileHeader, userId string) (fileName string, err error) { err = createUserFolder(userId) if err != nil { return "", err } f, err := fileHeader.Open() if err != nil { logrus.Errorln("Failed to open file header, err:", err) return "", err } fileData, err := io.ReadAll(f) if err != nil { logrus.Errorln("Failed to read file, err:", err) return "", err } fileName = uuid.New().String() newImage := bimg.NewImage(fileData).Image() err = bimg.Write(utils.GetUserStoragePath(userId)+fileName+".webp", newImage) if err != nil { logrus.Errorln("Failed to save image, err:", err) return "", err } return fileName + ".webp", nil } func GetImage(userId string, fileName string, imageSize string) ([]byte, error) { imgSize, err := strconv.Atoi(imageSize) if err != nil { imgSize = DefaultImageSize } buffer, err := bimg.Read(utils.GetUserStoragePath(userId) + fileName) if err != nil { logrus.Errorln("Failed to read image, err:", err) return []byte{}, err } // check that the value has not been manipulated and is greater than the largest index value in the list if imgSize > len(ImageSizes)-1 { imgSize = DefaultImageSize } resolution := ImageSizes[imgSize] newImage, err := bimg.NewImage(buffer).ForceResize(resolution, resolution) if err != nil { logrus.Errorln("Failed to force resize, err:", err) return []byte{}, err } return newImage, nil } func DeleteOldAvatarImage(userId string) error { path := utils.GetUserStoragePath(userId) dir, err := os.ReadDir(path) if err != nil { logrus.Errorln("Failed to read dir, err:", err) return err } for _, file := range dir { logrus.Println(file.Name()) os.Remove(path + file.Name()) } return nil }