完善站点运营设置:分路由管理、登录可见评论、邮件模板内联与关闭注册 SSR。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freefire/jiang13-bbs/model"
|
||||
"golang.org/x/image/webp"
|
||||
@@ -37,6 +39,7 @@ const (
|
||||
|
||||
// UploadService 附件上传:落盘到 data/uploads,元信息入库 attachments
|
||||
type UploadService struct {
|
||||
ops *Operations
|
||||
db *gorm.DB
|
||||
dir string // 上传根目录(如 data/uploads)
|
||||
setting *SettingService
|
||||
@@ -122,6 +125,17 @@ func (s *UploadService) SaveAvatar(userID uint, data []byte) (*model.Attachment,
|
||||
Height: cfg.Height,
|
||||
}
|
||||
|
||||
if s.ops != nil {
|
||||
id, e := s.ops.StoreFile(fullPath, att.MIME, true)
|
||||
if e != nil {
|
||||
_ = os.Remove(fullPath)
|
||||
return nil, e
|
||||
}
|
||||
if id != "" {
|
||||
att.URL = "/api/media/" + id
|
||||
_ = os.Remove(fullPath)
|
||||
}
|
||||
}
|
||||
// 附件记录与用户头像更新在同一事务内完成
|
||||
err = s.db.Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Create(att).Error; err != nil {
|
||||
@@ -204,6 +218,13 @@ func (s *UploadService) SaveImage(userID uint, src io.Reader) (*model.Attachment
|
||||
filename := hex.EncodeToString(nameBytes) + format.ext
|
||||
fullPath := filepath.Join(s.dir, "images", filename)
|
||||
tmp := fullPath + ".partial"
|
||||
if s.ops != nil {
|
||||
release, e := s.ops.BeginTemporary(tmp)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
defer release()
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(tmp, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644)
|
||||
if err != nil {
|
||||
@@ -270,6 +291,17 @@ func (s *UploadService) SaveImage(userID uint, src io.Reader) (*model.Attachment
|
||||
Width: w,
|
||||
Height: h,
|
||||
}
|
||||
if s.ops != nil {
|
||||
id, e := s.ops.StoreFile(fullPath, att.MIME, true)
|
||||
if e != nil {
|
||||
_ = os.Remove(fullPath)
|
||||
return nil, e
|
||||
}
|
||||
if id != "" {
|
||||
att.URL = "/api/media/" + id
|
||||
_ = os.Remove(fullPath)
|
||||
}
|
||||
}
|
||||
if err := s.db.Create(att).Error; err != nil {
|
||||
_ = os.Remove(fullPath)
|
||||
return nil, err
|
||||
@@ -310,6 +342,13 @@ func (s *UploadService) SaveBackground(src io.Reader) (string, error) {
|
||||
filename := hex.EncodeToString(nameBytes) + format.ext
|
||||
fullPath := filepath.Join(s.dir, "backgrounds", filename)
|
||||
tmp := fullPath + ".partial"
|
||||
if s.ops != nil {
|
||||
release, e := s.ops.BeginTemporary(tmp)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
defer release()
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(tmp, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644)
|
||||
if err != nil {
|
||||
@@ -370,6 +409,16 @@ func (s *UploadService) CopyBackgroundFromMedia(userID, attachmentID uint) (stri
|
||||
if err := s.db.Where("id = ? AND user_id = ?", attachmentID, userID).First(&att).Error; err != nil {
|
||||
return "", errors.New("图片不存在或不属于你")
|
||||
}
|
||||
if strings.HasPrefix(att.URL, "/api/media/") && s.ops != nil {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
r, _, e := s.ops.OpenObject(ctx, RemoteObjectID(att.URL), true)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
defer r.Close()
|
||||
return s.SaveBackground(r)
|
||||
}
|
||||
abs, ok := s.safeUploadPath(att.URL)
|
||||
if !ok {
|
||||
return "", errors.New("无效的图片地址")
|
||||
@@ -411,7 +460,7 @@ func (s *UploadService) RemoveBackgroundIfUnused(oldURL, siteURL, adminURL strin
|
||||
// UseAvatar 选用一张【本人历史上传】的头像
|
||||
func (s *UploadService) UseAvatar(userID uint, url string) error {
|
||||
url = strings.TrimSpace(url)
|
||||
if !strings.HasPrefix(url, "/uploads/avatars/") || len(url) > 512 {
|
||||
if (!strings.HasPrefix(url, "/uploads/avatars/") && !strings.HasPrefix(url, "/api/media/")) || len(url) > 512 {
|
||||
return errors.New("无效的头像地址")
|
||||
}
|
||||
var count int64
|
||||
@@ -469,6 +518,12 @@ func (s *UploadService) DeleteAttachment(userID, attachmentID uint) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.ops != nil && strings.HasPrefix(att.URL, "/api/media/") {
|
||||
if e := s.ops.RemoveObject(RemoteObjectID(att.URL)); e != nil {
|
||||
return errors.New("记录已删除,远程文件清理未完成,请联系管理员")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// DB 已清理后再删物理文件;文件删除失败只记日志(不影响用户侧结果)
|
||||
abs := filepath.Join(s.dir, filepath.FromSlash(strings.TrimPrefix(att.URL, "/uploads/")))
|
||||
if err := os.Remove(abs); err != nil && !os.IsNotExist(err) {
|
||||
@@ -476,3 +531,5 @@ func (s *UploadService) DeleteAttachment(userID, attachmentID uint) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *UploadService) WithOperations(o *Operations) { s.ops = o }
|
||||
|
||||
Reference in New Issue
Block a user