This is an automated email from the ASF dual-hosted git repository.
linkinstar pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/answer-plugins.git
The following commit(s) were added to refs/heads/main by this push:
new d6d9191 refactor(storage): Add support for attachment uploads
d6d9191 is described below
commit d6d9191424a2ce5015ab90a41e50a064fb3fcaed
Author: LinkinStars <[email protected]>
AuthorDate: Tue Nov 26 15:28:08 2024 +0800
refactor(storage): Add support for attachment uploads
---
storage-aliyunoss/README.md | 5 ++--
storage-aliyunoss/aliyunoss.go | 58 +++++++++++++++++-----------------------
storage-s3/README.md | 5 ++--
storage-s3/s3.go | 60 ++++++++++++++++++++----------------------
4 files changed, 57 insertions(+), 71 deletions(-)
diff --git a/storage-aliyunoss/README.md b/storage-aliyunoss/README.md
index 7516190..ca88796 100644
--- a/storage-aliyunoss/README.md
+++ b/storage-aliyunoss/README.md
@@ -1,4 +1,4 @@
-# Aliyun OSS Storage (preview)
+# Aliyun OSS Storage
> This plugin can be used to store attachments and avatars to Aliyun OSS.
## How to use
@@ -14,5 +14,4 @@
- `Object Key Prefix` - Prefix of the object key like 'answer/data/' that
ending with '/'
- `Access Key Id` - AccessKeyID of the AliCloud OSS storage
- `Access Key Secret` - AccessKeySecret of the AliCloud OSS storage
-- `Visit Url Prefix` - Prefix of access address for the uploaded file, ending
with '/' such as https://example.com/xxx/
-- `Max File Size` - Max file size in MB, default is 10MB
\ No newline at end of file
+- `Visit Url Prefix` - Prefix of access address for the uploaded file, ending
with '/' such as https://example.com/xxx/
\ No newline at end of file
diff --git a/storage-aliyunoss/aliyunoss.go b/storage-aliyunoss/aliyunoss.go
index af7cf36..153d177 100644
--- a/storage-aliyunoss/aliyunoss.go
+++ b/storage-aliyunoss/aliyunoss.go
@@ -26,10 +26,11 @@ import (
"encoding/json"
"fmt"
"path/filepath"
- "strconv"
"strings"
"time"
+ "github.com/apache/answer/pkg/checker"
+
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/apache/answer-plugins/storage-aliyunoss/i18n"
"github.com/apache/answer-plugins/util"
@@ -39,11 +40,6 @@ import (
//go:embed info.yaml
var Info embed.FS
-const (
- // 10MB
- defaultMaxFileSize int64 = 10 * 1024 * 1024
-)
-
type Storage struct {
Config *StorageConfig
}
@@ -55,7 +51,6 @@ type StorageConfig struct {
AccessKeyID string `json:"access_key_id"`
AccessKeySecret string `json:"access_key_secret"`
VisitUrlPrefix string `json:"visit_url_prefix"`
- MaxFileSize string `json:"max_file_size"`
}
func init() {
@@ -78,7 +73,7 @@ func (s *Storage) Info() plugin.Info {
}
}
-func (s *Storage) UploadFile(ctx *plugin.GinContext, source
plugin.UploadSource) (resp plugin.UploadFileResponse) {
+func (s *Storage) UploadFile(ctx *plugin.GinContext, condition
plugin.UploadFileCondition) (resp plugin.UploadFileResponse) {
resp = plugin.UploadFileResponse{}
client, err := oss.New(s.Config.Endpoint, s.Config.AccessKeyID,
s.Config.AccessKeySecret)
if err != nil {
@@ -101,13 +96,13 @@ func (s *Storage) UploadFile(ctx *plugin.GinContext,
source plugin.UploadSource)
return resp
}
- if !s.CheckFileType(file.Filename, source) {
+ if s.IsUnsupportedFileType(file.Filename, condition) {
resp.OriginalError = fmt.Errorf("file type not allowed")
resp.DisplayErrorMsg =
plugin.MakeTranslator(i18n.ErrUnsupportedFileType)
return resp
}
- if file.Size > s.maxFileSizeLimit() {
+ if s.ExceedFileSizeLimit(file.Size, condition) {
resp.OriginalError = fmt.Errorf("file size too large")
resp.DisplayErrorMsg =
plugin.MakeTranslator(i18n.ErrOverFileSizeLimit)
return resp
@@ -121,7 +116,7 @@ func (s *Storage) UploadFile(ctx *plugin.GinContext, source
plugin.UploadSource)
}
defer open.Close()
- objectKey := s.createObjectKey(file.Filename, source)
+ objectKey := s.createObjectKey(file.Filename, condition.Source)
request := &oss.PutObjectRequest{
ObjectKey: objectKey,
Reader: open,
@@ -145,6 +140,8 @@ func (s *Storage) createObjectKey(originalFilename string,
source plugin.UploadS
return s.Config.ObjectKeyPrefix + "avatar/" + randomString + ext
case plugin.UserPost:
return s.Config.ObjectKeyPrefix + "post/" + randomString + ext
+ case plugin.UserPostAttachment:
+ return s.Config.ObjectKeyPrefix + "attachment/" + randomString
+ ext
case plugin.AdminBranding:
return s.Config.ObjectKeyPrefix + "branding/" + randomString +
ext
default:
@@ -158,23 +155,27 @@ func (s *Storage) randomObjectKey() string {
return fmt.Sprintf("%d", time.Now().UnixNano()) +
hex.EncodeToString(bytes)
}
-func (s *Storage) CheckFileType(originalFilename string, source
plugin.UploadSource) bool {
- ext := strings.ToLower(filepath.Ext(originalFilename))
- if _, ok := plugin.DefaultFileTypeCheckMapping[source][ext]; ok {
+func (s *Storage) IsUnsupportedFileType(originalFilename string, condition
plugin.UploadFileCondition) bool {
+ if condition.Source == plugin.AdminBranding || condition.Source ==
plugin.UserAvatar {
+ ext := strings.ToLower(filepath.Ext(originalFilename))
+ if _, ok :=
plugin.DefaultFileTypeCheckMapping[condition.Source][ext]; ok {
+ return false
+ }
return true
}
- return false
-}
-func (s *Storage) maxFileSizeLimit() int64 {
- if len(s.Config.MaxFileSize) == 0 {
- return defaultMaxFileSize
+ // check the post image and attachment file type check
+ if condition.Source == plugin.UserPost {
+ return checker.IsUnAuthorizedExtension(originalFilename,
condition.AuthorizedImageExtensions)
}
- limit, _ := strconv.Atoi(s.Config.MaxFileSize)
- if limit <= 0 {
- return defaultMaxFileSize
+ return checker.IsUnAuthorizedExtension(originalFilename,
condition.AuthorizedAttachmentExtensions)
+}
+
+func (s *Storage) ExceedFileSizeLimit(fileSize int64, condition
plugin.UploadFileCondition) bool {
+ if condition.Source == plugin.UserPostAttachment {
+ return fileSize > int64(condition.MaxAttachmentSize)*1024*1024
}
- return int64(limit) * 1024 * 1024
+ return fileSize > int64(condition.MaxImageSize)*1024*1024
}
func (s *Storage) ConfigFields() []plugin.ConfigField {
@@ -245,17 +246,6 @@ func (s *Storage) ConfigFields() []plugin.ConfigField {
},
Value: s.Config.VisitUrlPrefix,
},
- {
- Name: "max_file_size",
- Type: plugin.ConfigTypeInput,
- Title:
plugin.MakeTranslator(i18n.ConfigMaxFileSizeTitle),
- Description:
plugin.MakeTranslator(i18n.ConfigMaxFileSizeDescription),
- Required: false,
- UIOptions: plugin.ConfigFieldUIOptions{
- InputType: plugin.InputTypeNumber,
- },
- Value: s.Config.MaxFileSize,
- },
}
}
diff --git a/storage-s3/README.md b/storage-s3/README.md
index 0fb39b2..23d8bd4 100644
--- a/storage-s3/README.md
+++ b/storage-s3/README.md
@@ -1,4 +1,4 @@
-# S3 Storage (preview)
+# S3 Storage
> This plugin can be used to store attachments and avatars to AWS S3.
## How to use
@@ -15,5 +15,4 @@
- `Access Key Id` - AccessKeyId of the S3
- `Access Key Secret` - AccessKeySecret of the S3
- `Access Token` - AccessToken of the S3
-- `Visit Url Prefix` - Prefix of access address for the uploaded file, ending
with '/' such as https://example.com/xxx/
-- `Max File Size` - Max file size in MB, default is 10MB
\ No newline at end of file
+- `Visit Url Prefix` - Prefix of access address for the uploaded file, ending
with '/' such as https://example.com/xxx/
\ No newline at end of file
diff --git a/storage-s3/s3.go b/storage-s3/s3.go
index 2cf2976..56f49b2 100644
--- a/storage-s3/s3.go
+++ b/storage-s3/s3.go
@@ -26,23 +26,18 @@ import (
"encoding/json"
"fmt"
"path/filepath"
- "strconv"
"strings"
"time"
"github.com/apache/answer-plugins/storage-s3/i18n"
"github.com/apache/answer-plugins/util"
+ "github.com/apache/answer/pkg/checker"
"github.com/apache/answer/plugin"
)
//go:embed info.yaml
var Info embed.FS
-const (
- // 10MB
- defaultMaxFileSize int64 = 10 * 1024 * 1024
-)
-
type Storage struct {
Config *StorageConfig
Client *Client
@@ -81,7 +76,7 @@ func (s *Storage) Info() plugin.Info {
}
}
-func (s *Storage) UploadFile(ctx *plugin.GinContext, source
plugin.UploadFileCondition) (resp plugin.UploadFileResponse) {
+func (s *Storage) UploadFile(ctx *plugin.GinContext, condition
plugin.UploadFileCondition) (resp plugin.UploadFileResponse) {
resp = plugin.UploadFileResponse{}
file, err := ctx.FormFile("file")
@@ -91,13 +86,13 @@ func (s *Storage) UploadFile(ctx *plugin.GinContext, source
plugin.UploadFileCon
return resp
}
- if !s.checkFileType(file.Filename, condition.Source) {
+ if s.IsUnsupportedFileType(file.Filename, condition) {
resp.OriginalError = fmt.Errorf("file type not allowed")
resp.DisplayErrorMsg =
plugin.MakeTranslator(i18n.ErrUnsupportedFileType)
return resp
}
- if file.Size > s.maxFileSizeLimit() {
+ if s.ExceedFileSizeLimit(file.Size, condition) {
resp.OriginalError = fmt.Errorf("file size too large")
resp.DisplayErrorMsg =
plugin.MakeTranslator(i18n.ErrOverFileSizeLimit)
return resp
@@ -122,6 +117,29 @@ func (s *Storage) UploadFile(ctx *plugin.GinContext,
source plugin.UploadFileCon
return resp
}
+func (s *Storage) IsUnsupportedFileType(originalFilename string, condition
plugin.UploadFileCondition) bool {
+ if condition.Source == plugin.AdminBranding || condition.Source ==
plugin.UserAvatar {
+ ext := strings.ToLower(filepath.Ext(originalFilename))
+ if _, ok :=
plugin.DefaultFileTypeCheckMapping[condition.Source][ext]; ok {
+ return false
+ }
+ return true
+ }
+
+ // check the post image and attachment file type check
+ if condition.Source == plugin.UserPost {
+ return checker.IsUnAuthorizedExtension(originalFilename,
condition.AuthorizedImageExtensions)
+ }
+ return checker.IsUnAuthorizedExtension(originalFilename,
condition.AuthorizedAttachmentExtensions)
+}
+
+func (s *Storage) ExceedFileSizeLimit(fileSize int64, condition
plugin.UploadFileCondition) bool {
+ if condition.Source == plugin.UserPostAttachment {
+ return fileSize > int64(condition.MaxAttachmentSize)*1024*1024
+ }
+ return fileSize > int64(condition.MaxImageSize)*1024*1024
+}
+
func (s *Storage) createObjectKey(originalFilename string, source
plugin.UploadSource) string {
ext := strings.ToLower(filepath.Ext(originalFilename))
randomString := s.randomObjectKey()
@@ -130,6 +148,8 @@ func (s *Storage) createObjectKey(originalFilename string,
source plugin.UploadS
return s.Config.ObjectKeyPrefix + "avatar/" + randomString + ext
case plugin.UserPost:
return s.Config.ObjectKeyPrefix + "post/" + randomString + ext
+ case plugin.UserPostAttachment:
+ return s.Config.ObjectKeyPrefix + "attachment/" + randomString
+ ext
case plugin.AdminBranding:
return s.Config.ObjectKeyPrefix + "branding/" + randomString +
ext
default:
@@ -151,17 +171,6 @@ func (s *Storage) checkFileType(originalFilename string,
source plugin.UploadSou
return false
}
-func (s *Storage) maxFileSizeLimit() int64 {
- if len(s.Config.MaxFileSize) == 0 {
- return defaultMaxFileSize
- }
- limit, _ := strconv.Atoi(s.Config.MaxFileSize)
- if limit <= 0 {
- return defaultMaxFileSize
- }
- return int64(limit) * 1024 * 1024
-}
-
func (s *Storage) ConfigFields() []plugin.ConfigField {
return []plugin.ConfigField{
{
@@ -241,17 +250,6 @@ func (s *Storage) ConfigFields() []plugin.ConfigField {
},
Value: s.Config.VisitUrlPrefix,
},
- {
- Name: "max_file_size",
- Type: plugin.ConfigTypeInput,
- Title:
plugin.MakeTranslator(i18n.ConfigMaxFileSizeTitle),
- Description:
plugin.MakeTranslator(i18n.ConfigMaxFileSizeDescription),
- Required: false,
- UIOptions: plugin.ConfigFieldUIOptions{
- InputType: plugin.InputTypeNumber,
- },
- Value: s.Config.MaxFileSize,
- },
{
Name: "region",
Type: plugin.ConfigTypeInput,