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) (

Reply via email to