This is an automated email from the ASF dual-hosted git repository.
linkinstar pushed a commit to branch test
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git
The following commit(s) were added to refs/heads/test by this push:
new c5321149 feat(file): implement file download functionality
c5321149 is described below
commit c5321149a1b7fdd5f066c3f24a74d5682a447d27
Author: LinkinStars <[email protected]>
AuthorDate: Tue Dec 3 17:36:01 2024 +0800
feat(file): implement file download functionality
---
internal/router/static_router.go | 17 +++++++++++++++++
internal/service/uploader/upload.go | 19 ++++++++++++++-----
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/internal/router/static_router.go b/internal/router/static_router.go
index 5b087431..3fbb12da 100644
--- a/internal/router/static_router.go
+++ b/internal/router/static_router.go
@@ -22,6 +22,8 @@ package router
import (
"github.com/apache/incubator-answer/internal/service/service_config"
"github.com/gin-gonic/gin"
+ "path/filepath"
+ "strings"
)
// StaticRouter static api router
@@ -39,4 +41,19 @@ func NewStaticRouter(serviceConfig
*service_config.ServiceConfig) *StaticRouter
// RegisterStaticRouter register static api router
func (a *StaticRouter) RegisterStaticRouter(r *gin.RouterGroup) {
r.Static("/uploads", a.serviceConfig.UploadPath)
+
+ r.GET("/download/*filepath", func(c *gin.Context) {
+ // The filePath such as /download/hash/123.png
+ filePath := c.Param("filepath")
+ // The download filename is 123.png
+ downloadFilename := filepath.Base(filePath)
+
+ // After trimming, the downloadLink is /uploads/hash
+ downloadLink := strings.TrimSuffix(filePath,
"/"+downloadFilename)
+ // After add the extension, the downloadLink is
/uploads/hash.png
+ downloadLink += filepath.Ext(downloadFilename)
+
+ downloadLink = filepath.Join(a.serviceConfig.UploadPath,
downloadLink)
+ c.FileAttachment(downloadLink, downloadFilename)
+ })
}
diff --git a/internal/service/uploader/upload.go
b/internal/service/uploader/upload.go
index a8d9c0cc..6baf00d1 100644
--- a/internal/service/uploader/upload.go
+++ b/internal/service/uploader/upload.go
@@ -25,6 +25,7 @@ import (
"io"
"mime/multipart"
"net/http"
+ "net/url"
"os"
"path"
"path/filepath"
@@ -237,7 +238,7 @@ func (us *uploaderService) UploadPostAttachment(ctx
*gin.Context) (
fileExt := strings.ToLower(path.Ext(fileHeader.Filename))
newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt)
avatarFilePath := path.Join(postSubPath, newFilename)
- return us.uploadAttachmentFile(ctx, fileHeader, avatarFilePath)
+ return us.uploadAttachmentFile(ctx, fileHeader, fileHeader.Filename,
avatarFilePath)
}
func (us *uploaderService) UploadBrandingFile(ctx *gin.Context) (
@@ -304,8 +305,8 @@ func (us *uploaderService) uploadImageFile(ctx
*gin.Context, file *multipart.Fil
return url, nil
}
-func (us *uploaderService) uploadAttachmentFile(ctx *gin.Context, file
*multipart.FileHeader, fileSubPath string) (
- url string, err error) {
+func (us *uploaderService) uploadAttachmentFile(ctx *gin.Context, file
*multipart.FileHeader, originalFilename, fileSubPath string) (
+ downloadUrl string, err error) {
siteGeneral, err := us.siteInfoService.GetSiteGeneral(ctx)
if err != nil {
return "", err
@@ -315,8 +316,16 @@ func (us *uploaderService) uploadAttachmentFile(ctx
*gin.Context, file *multipar
return "",
errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
}
- url = fmt.Sprintf("%s/uploads/%s", siteGeneral.SiteUrl, fileSubPath)
- return url, nil
+ // The original filename is 123.png
+ // The local saved path is /UploadPath/hash.png
+ // The download link wil be /download/hash/123.png.
+ // When downloading, the download link will be redirect to the local
saved path. And the download filename will be 123.png.
+ ext := filepath.Ext(fileSubPath)
+ // Need url encode the original filename. Because the filename may
contain special characters that conflict with the markdown syntax.
+ originalFilename = url.QueryEscape(originalFilename)
+ downloadPath := strings.TrimSuffix(fileSubPath, ext) + "/" +
originalFilename
+ downloadUrl = fmt.Sprintf("%s/download/%s", siteGeneral.SiteUrl,
downloadPath)
+ return downloadUrl, nil
}
func (us *uploaderService) tryToUploadByPlugin(ctx *gin.Context, source
plugin.UploadSource) (