mirror of
https://github.com/keven1024/015.git
synced 2026-05-26 07:08:02 +00:00
245 lines
6.9 KiB
Go
245 lines
6.9 KiB
Go
package controllers
|
||
|
||
import (
|
||
"backend/internal/utils"
|
||
"encoding/json"
|
||
"pkg/models"
|
||
u "pkg/utils"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/hibiken/asynq"
|
||
"github.com/labstack/echo/v5"
|
||
gonanoid "github.com/matoous/go-nanoid/v2"
|
||
"github.com/spf13/cast"
|
||
)
|
||
|
||
type CreateShareProps struct {
|
||
Type models.ShareType `json:"type"`
|
||
// ShareId string `json:"id"`
|
||
Config ShareConfig `json:"config"`
|
||
Data string `json:"data"`
|
||
FileName string `json:"file_name"`
|
||
}
|
||
|
||
type ShareConfig struct {
|
||
ExpireAt int `json:"expire_time"` // 分钟
|
||
ViewNum int64 `json:"download_nums"`
|
||
HasPassword bool `json:"has_password"`
|
||
Password string `json:"password"`
|
||
HasNotify bool `json:"has_notify"`
|
||
NotifyTypes []string `json:"notify_types"`
|
||
NotifyEmails []string `json:"notify_emails"`
|
||
NotifyWebhooks []models.NotifyWebhook `json:"notify_webhooks"`
|
||
Locale string `json:"locale"`
|
||
HasPickupCode bool `json:"has_pickup_code"`
|
||
}
|
||
|
||
func CreateShareInfo(c *echo.Context) error {
|
||
owner, _ := echo.ContextGet[string](c, "auth")
|
||
|
||
r := new(CreateShareProps)
|
||
if err := c.Bind(r); err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
if r.Config.ExpireAt < 1 {
|
||
return utils.HTTPErrorHandler(c, ErrInvalidRequest)
|
||
}
|
||
ExpireTime := time.Now().Add(time.Duration(r.Config.ExpireAt) * time.Minute)
|
||
if r.Data == "" || (r.Type != models.ShareTypeFile && r.Type != models.ShareTypeText) || ExpireTime.Before(time.Now()) || r.Config.ViewNum < 1 {
|
||
return utils.HTTPErrorHandler(c, ErrInvalidRequest)
|
||
}
|
||
|
||
id, err := gonanoid.New()
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
|
||
if r.Type == models.ShareTypeFile {
|
||
fileInfo, err := models.GetRedisFileInfo(r.Data)
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
if fileInfo == nil {
|
||
return utils.HTTPErrorHandler(c, ErrShareFileNotFound)
|
||
}
|
||
if fileInfo.FileType != models.FileTypeUpload {
|
||
return utils.HTTPErrorHandler(c, ErrInvalidShareFileState)
|
||
}
|
||
}
|
||
password := ""
|
||
if r.Config.Password != "" {
|
||
hash, err := utils.GeneratePasswordHash(r.Config.Password)
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
password = hash
|
||
}
|
||
|
||
var notifyEmails []string
|
||
var notifyWebhooks []models.NotifyWebhook
|
||
if r.Config.HasNotify {
|
||
hasEmail, hasWebhook := false, false
|
||
for _, nt := range r.Config.NotifyTypes {
|
||
switch nt {
|
||
case "email":
|
||
hasEmail = true
|
||
case "webhook":
|
||
hasWebhook = true
|
||
default:
|
||
return utils.HTTPErrorHandler(c, ErrInvalidRequest)
|
||
}
|
||
}
|
||
if hasEmail {
|
||
notifyEmails = r.Config.NotifyEmails
|
||
}
|
||
if hasWebhook {
|
||
notifyWebhooks = r.Config.NotifyWebhooks
|
||
}
|
||
}
|
||
|
||
_, err = models.SetRedisShareInfo(id, func(shareInfo *models.RedisShareInfo) *models.RedisShareInfo {
|
||
shareInfo.Data = r.Data
|
||
shareInfo.Type = r.Type
|
||
shareInfo.CreatedAt = time.Now().Unix()
|
||
shareInfo.Owner = owner
|
||
shareInfo.ViewNum = r.Config.ViewNum
|
||
shareInfo.Password = password
|
||
shareInfo.FileName = r.FileName
|
||
shareInfo.NotifyEmails = notifyEmails
|
||
shareInfo.NotifyWebhooks = notifyWebhooks
|
||
shareInfo.Locale = r.Config.Locale
|
||
shareInfo.ExpireAt = ExpireTime.Unix()
|
||
return shareInfo
|
||
})
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
var pickupCode string
|
||
if r.Config.HasPickupCode {
|
||
for {
|
||
pickupCode = utils.GeneratePickupCode()
|
||
ok, err := models.SetRedisPickupData(pickupCode, id)
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
if !ok {
|
||
continue
|
||
}
|
||
break
|
||
}
|
||
}
|
||
|
||
if r.Type == models.ShareTypeFile {
|
||
shareIDs, err := models.GetRedisFileShareRelational(r.Data)
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
shareIDs = append(shareIDs, id)
|
||
err = models.SetRedisFileShareRelational(r.Data, shareIDs)
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
client := u.GetQueueClient()
|
||
json, err := json.Marshal(map[string]any{"share_id": id, "file_id": r.Data})
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
// 这里延时分享过期时间基础上加下载窗口期后1小时删除,防止用户过期前几分钟才开始下载,下载一半文件不见了
|
||
downloadWindow := u.GetEnvWithDefault("share.download_window", "12")
|
||
deleteTime := time.Duration(r.Config.ExpireAt)*time.Minute + cast.ToDuration(downloadWindow+"h") + 1*time.Hour
|
||
_, err = client.Enqueue(asynq.NewTask("share:remove", json), asynq.ProcessIn(deleteTime))
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
}
|
||
|
||
// 统计分享数
|
||
currentDate := time.Now().Format("2006-01-02")
|
||
_, err = models.SetRedisStat(currentDate, func(stat *models.StatData) *models.StatData {
|
||
stat.ShareNum += 1
|
||
return stat
|
||
})
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
|
||
return utils.HTTPSuccessHandler(c, map[string]any{
|
||
"id": id,
|
||
"file_name": r.FileName,
|
||
"download_nums": r.Config.ViewNum,
|
||
"expire_at": ExpireTime.Unix(),
|
||
"pickup_code": pickupCode,
|
||
})
|
||
}
|
||
|
||
type GetShareProps struct {
|
||
ShareId string `param:"id"`
|
||
}
|
||
|
||
func GetShareInfo(c *echo.Context) error {
|
||
shareId := c.Param("id")
|
||
if shareId == "" {
|
||
return utils.HTTPErrorHandler(c, ErrInvalidRequest)
|
||
}
|
||
|
||
shareInfo, err := models.GetRedisShareInfo(shareId)
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
if shareInfo == nil || shareInfo.ViewNum < 1 {
|
||
return utils.HTTPErrorHandler(c, ErrShareNotFound)
|
||
}
|
||
|
||
if shareInfo.Type == models.ShareTypeFile {
|
||
fileInfo, err := models.GetRedisFileInfo(shareInfo.Data)
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
if fileInfo == nil {
|
||
return utils.HTTPErrorHandler(c, ErrShareFileNotFound)
|
||
}
|
||
if fileInfo.FileType != models.FileTypeUpload {
|
||
return utils.HTTPErrorHandler(c, ErrInvalidShareFileState)
|
||
}
|
||
return utils.HTTPSuccessHandler(c, map[string]any{
|
||
"id": shareId,
|
||
"type": shareInfo.Type,
|
||
"name": shareInfo.FileName,
|
||
"download_nums": shareInfo.ViewNum,
|
||
"has_password": shareInfo.Password != "",
|
||
"expire_at": shareInfo.ExpireAt,
|
||
"owner": shareInfo.Owner,
|
||
"size": fileInfo.FileSize,
|
||
"mime_type": fileInfo.MimeType,
|
||
})
|
||
}
|
||
|
||
return utils.HTTPSuccessHandler(c, map[string]any{
|
||
"id": shareId,
|
||
"type": shareInfo.Type,
|
||
"name": shareInfo.FileName,
|
||
"download_nums": shareInfo.ViewNum,
|
||
"has_password": shareInfo.Password != "",
|
||
"expire_at": shareInfo.ExpireAt,
|
||
"owner": shareInfo.Owner,
|
||
})
|
||
}
|
||
|
||
func GetShareByPickupCode(c *echo.Context) error {
|
||
pickupCode := c.Param("code")
|
||
if pickupCode == "" {
|
||
return utils.HTTPErrorHandler(c, ErrInvalidRequest)
|
||
}
|
||
shareId, err := models.GetRedisPickupData(strings.ToUpper(pickupCode))
|
||
if err != nil {
|
||
return utils.HTTPErrorHandler(c, err)
|
||
}
|
||
if shareId == "" {
|
||
return utils.HTTPErrorHandler(c, ErrShareNotFound)
|
||
}
|
||
return utils.HTTPSuccessHandler(c, map[string]any{
|
||
"share_id": shareId,
|
||
})
|
||
}
|