mirror of https://github.com/rocboss/paopao-ce
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
306 lines
7.8 KiB
306 lines
7.8 KiB
package api
|
|
|
|
import (
|
|
"image"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
|
"github.com/disintegration/imaging"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/gofrs/uuid"
|
|
"github.com/rocboss/paopao-ce/global"
|
|
"github.com/rocboss/paopao-ce/internal/model"
|
|
"github.com/rocboss/paopao-ce/internal/service"
|
|
"github.com/rocboss/paopao-ce/pkg/app"
|
|
"github.com/rocboss/paopao-ce/pkg/convert"
|
|
"github.com/rocboss/paopao-ce/pkg/errcode"
|
|
)
|
|
|
|
func GeneratePath(s string) string {
|
|
n := len(s)
|
|
if n <= 2 {
|
|
return s
|
|
}
|
|
|
|
return GeneratePath(s[:n-2]) + "/" + s[n-2:]
|
|
}
|
|
|
|
func GetFileExt(s string) (string, error) {
|
|
switch s {
|
|
case "image/png":
|
|
return ".png", nil
|
|
case "image/jpg":
|
|
return ".jpg", nil
|
|
case "image/jpeg":
|
|
return ".jpeg", nil
|
|
case "image/gif":
|
|
return ".gif", nil
|
|
case "video/mp4":
|
|
return ".mp4", nil
|
|
case "video/quicktime":
|
|
return ".mov", nil
|
|
case "application/zip":
|
|
return ".zip", nil
|
|
default:
|
|
return "", errcode.FileInvalidExt.WithDetails("仅允许 png/jpg/gif/mp4/mov/zip 类型")
|
|
}
|
|
}
|
|
func GetImageSize(img image.Rectangle) (int, int) {
|
|
b := img.Bounds()
|
|
width := b.Max.X
|
|
height := b.Max.Y
|
|
return width, height
|
|
}
|
|
|
|
func fileCheck(uploadType string, size int64) error {
|
|
if uploadType != "public/video" &&
|
|
uploadType != "public/image" &&
|
|
uploadType != "public/avatar" &&
|
|
uploadType != "attachment" {
|
|
return errcode.InvalidParams
|
|
}
|
|
|
|
if size > 1024*1024*100 {
|
|
return errcode.FileInvalidSize.WithDetails("最大允许100MB")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func UploadAttachment(c *gin.Context) {
|
|
response := app.NewResponse(c)
|
|
|
|
uploadType := c.Request.FormValue("type")
|
|
file, fileHeader, err := c.Request.FormFile("file")
|
|
if err != nil {
|
|
global.Logger.Errorf("api.UploadAttachment err: %v", err)
|
|
response.ToErrorResponse(errcode.FileUploadFailed)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
if err = fileCheck(uploadType, fileHeader.Size); err != nil {
|
|
cErr, _ := err.(*errcode.Error)
|
|
response.ToErrorResponse(cErr)
|
|
return
|
|
}
|
|
|
|
fileExt, err := GetFileExt(fileHeader.Header.Get("Content-Type"))
|
|
if err != nil {
|
|
global.Logger.Errorf("GetFileExt err: %v", err)
|
|
response.ToErrorResponse(err.(*errcode.Error))
|
|
return
|
|
}
|
|
|
|
fileReader, err := fileHeader.Open()
|
|
if err != nil {
|
|
global.Logger.Errorf("Attachment file read err: %v", err)
|
|
response.ToErrorResponse(errcode.FileUploadFailed)
|
|
return
|
|
}
|
|
defer fileReader.Close()
|
|
|
|
// 生成随机路径
|
|
randomPath := uuid.Must(uuid.NewV4()).String()
|
|
ossSavePath := uploadType + "/" + GeneratePath(randomPath[:8]) + "/" + randomPath[9:] + fileExt
|
|
|
|
client, err := oss.New(global.AliossSetting.AliossEndpoint, global.AliossSetting.AliossAccessKeyID, global.AliossSetting.AliossAccessKeySecret)
|
|
if err != nil {
|
|
global.Logger.Errorf("oss.New err: %v", err)
|
|
response.ToErrorResponse(errcode.FileUploadFailed)
|
|
return
|
|
}
|
|
|
|
bucket, err := client.Bucket("paopao-assets")
|
|
if err != nil {
|
|
global.Logger.Errorf("client.Bucket err: %v", err)
|
|
response.ToErrorResponse(errcode.FileUploadFailed)
|
|
return
|
|
}
|
|
|
|
err = bucket.PutObject(ossSavePath, fileReader)
|
|
if err != nil {
|
|
global.Logger.Errorf("bucket.PutObject err: %v", err)
|
|
response.ToErrorResponse(errcode.FileUploadFailed)
|
|
return
|
|
}
|
|
|
|
// 构造附件Model
|
|
attachment := &model.Attachment{
|
|
FileSize: fileHeader.Size,
|
|
Content: "https://" + global.AliossSetting.AliossDomain + "/" + ossSavePath,
|
|
}
|
|
|
|
if userID, exists := c.Get("UID"); exists {
|
|
attachment.UserID = userID.(int64)
|
|
}
|
|
|
|
var uploadAttachmentTypeMap = map[string]model.AttachmentType{
|
|
"public/image": model.ATTACHMENT_TYPE_IMAGE,
|
|
"public/avatar": model.ATTACHMENT_TYPE_IMAGE,
|
|
"public/video": model.ATTACHMENT_TYPE_VIDEO,
|
|
"attachment": model.ATTACHMENT_TYPE_OTHER,
|
|
}
|
|
|
|
attachment.Type = uploadAttachmentTypeMap[uploadType]
|
|
if attachment.Type == model.ATTACHMENT_TYPE_IMAGE {
|
|
var src image.Image
|
|
src, err = imaging.Decode(file)
|
|
if err == nil {
|
|
attachment.ImgWidth, attachment.ImgHeight = GetImageSize(src.Bounds())
|
|
}
|
|
}
|
|
|
|
attachment, err = service.CreateAttachment(attachment)
|
|
if err != nil {
|
|
global.Logger.Errorf("service.CreateAttachment err: %v", err)
|
|
response.ToErrorResponse(errcode.FileUploadFailed)
|
|
}
|
|
|
|
response.ToResponse(attachment)
|
|
}
|
|
|
|
func DownloadAttachmentPrecheck(c *gin.Context) {
|
|
response := app.NewResponse(c)
|
|
|
|
contentID := convert.StrTo(c.Query("id")).MustInt64()
|
|
// 加载content
|
|
content, err := service.GetPostContentByID(contentID)
|
|
if err != nil {
|
|
global.Logger.Errorf("service.GetPostContentByID err: %v", err)
|
|
response.ToErrorResponse(errcode.InvalidDownloadReq)
|
|
}
|
|
user, _ := c.Get("USER")
|
|
if content.Type == model.CONTENT_TYPE_CHARGE_ATTACHMENT {
|
|
// 加载post
|
|
post, err := service.GetPost(content.PostID)
|
|
if err != nil {
|
|
global.Logger.Errorf("service.GetPost err: %v", err)
|
|
response.ToResponse(gin.H{
|
|
"paid": false,
|
|
})
|
|
return
|
|
}
|
|
|
|
// 发布者或管理员免费下载
|
|
if post.UserID == user.(*model.User).ID || user.(*model.User).IsAdmin {
|
|
response.ToResponse(gin.H{
|
|
"paid": true,
|
|
})
|
|
return
|
|
}
|
|
|
|
// 检测是否有购买记录
|
|
response.ToResponse(gin.H{
|
|
"paid": service.CheckPostAttachmentIsPaid(post.ID, user.(*model.User).ID),
|
|
})
|
|
return
|
|
}
|
|
response.ToResponse(gin.H{
|
|
"paid": false,
|
|
})
|
|
}
|
|
|
|
func DownloadAttachment(c *gin.Context) {
|
|
response := app.NewResponse(c)
|
|
|
|
contentID := convert.StrTo(c.Query("id")).MustInt64()
|
|
|
|
// 加载content
|
|
content, err := service.GetPostContentByID(contentID)
|
|
if err != nil {
|
|
global.Logger.Errorf("service.GetPostContentByID err: %v", err)
|
|
response.ToErrorResponse(errcode.InvalidDownloadReq)
|
|
}
|
|
|
|
// 收费附件
|
|
if content.Type == model.CONTENT_TYPE_CHARGE_ATTACHMENT {
|
|
user, _ := c.Get("USER")
|
|
|
|
// 加载post
|
|
post, err := service.GetPost(content.PostID)
|
|
if err != nil {
|
|
global.Logger.Errorf("service.GetPost err: %v", err)
|
|
response.ToResponse(gin.H{
|
|
"paid": false,
|
|
})
|
|
return
|
|
}
|
|
|
|
paidFlag := false
|
|
|
|
// 发布者或管理员免费下载
|
|
if post.UserID == user.(*model.User).ID || user.(*model.User).IsAdmin {
|
|
paidFlag = true
|
|
}
|
|
|
|
// 检测是否有购买记录
|
|
if service.CheckPostAttachmentIsPaid(post.ID, user.(*model.User).ID) {
|
|
paidFlag = true
|
|
}
|
|
|
|
if !paidFlag {
|
|
// 未购买,则尝试购买
|
|
err := service.BuyPostAttachment(&model.Post{
|
|
Model: &model.Model{
|
|
ID: post.ID,
|
|
},
|
|
UserID: post.UserID,
|
|
AttachmentPrice: post.AttachmentPrice,
|
|
}, user.(*model.User))
|
|
if err != nil {
|
|
global.Logger.Errorf("service.BuyPostAttachment err: %v", err)
|
|
if err == errcode.InsuffientDownloadMoney {
|
|
|
|
response.ToErrorResponse(errcode.InsuffientDownloadMoney)
|
|
} else {
|
|
|
|
response.ToErrorResponse(errcode.DownloadExecFail)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// 开始构造下载地址
|
|
client, err := oss.New(global.AliossSetting.AliossEndpoint, global.AliossSetting.AliossAccessKeyID, global.AliossSetting.AliossAccessKeySecret)
|
|
if err != nil {
|
|
global.Logger.Errorf("oss.New err: %v", err)
|
|
response.ToErrorResponse(errcode.DownloadReqError)
|
|
return
|
|
}
|
|
|
|
bucket, err := client.Bucket("paopao-assets")
|
|
if err != nil {
|
|
global.Logger.Errorf("client.Bucket err: %v", err)
|
|
response.ToErrorResponse(errcode.DownloadReqError)
|
|
return
|
|
}
|
|
|
|
// 签名
|
|
objectKey := strings.Replace(content.Content, "https://"+global.AliossSetting.AliossDomain+"/", "", -1)
|
|
signedURL, err := bucket.SignURL(objectKey, oss.HTTPGet, 60)
|
|
if err != nil {
|
|
global.Logger.Errorf("client.SignURL err: %v", err)
|
|
response.ToErrorResponse(errcode.DownloadReqError)
|
|
return
|
|
}
|
|
ur, err := url.Parse(signedURL)
|
|
if err != nil {
|
|
global.Logger.Errorf("url.Parse err: %v", err)
|
|
response.ToErrorResponse(errcode.DownloadReqError)
|
|
return
|
|
}
|
|
epath, err := url.PathUnescape(ur.Path)
|
|
if err != nil {
|
|
global.Logger.Errorf("url.PathUnescape err: %v", err)
|
|
response.ToErrorResponse(errcode.DownloadReqError)
|
|
return
|
|
}
|
|
|
|
ur.Path = epath
|
|
ur.RawPath = epath
|
|
response.ToResponse(ur.String())
|
|
}
|