fix: 记录视频上传预览与入口错误
This commit is contained in:
@@ -960,7 +960,12 @@ func (a *App) DownloadVideos(productIDs []string) error {
|
||||
|
||||
// GetUploadPreview 只扫描本地磁盘并执行本地预检;批量确认框不发远端请求。
|
||||
// 单商品保留 R5 首版的覆盖警告,因此额外读取一次远端当前状态。
|
||||
func (a *App) GetUploadPreview(productIDs []string) (UploadPreview, error) {
|
||||
func (a *App) GetUploadPreview(productIDs []string) (preview UploadPreview, previewErr error) {
|
||||
defer func() {
|
||||
if previewErr != nil && a.log != nil {
|
||||
a.log.Error("上传预览失败:%s", uploadRequestSummary(previewErr))
|
||||
}
|
||||
}()
|
||||
if a.db == nil {
|
||||
return UploadPreview{}, fmt.Errorf("数据库未就绪,请查看运行日志")
|
||||
}
|
||||
@@ -968,7 +973,7 @@ func (a *App) GetUploadPreview(productIDs []string) (UploadPreview, error) {
|
||||
if len(ids) == 0 {
|
||||
return UploadPreview{}, fmt.Errorf("请先勾选要上传的商品")
|
||||
}
|
||||
preview := UploadPreview{Total: len(ids)}
|
||||
preview = UploadPreview{Total: len(ids)}
|
||||
var single store.Product
|
||||
for _, productID := range ids {
|
||||
product, found, err := a.db.GetProduct(productID)
|
||||
|
||||
+19
-1
@@ -16,7 +16,12 @@ import (
|
||||
)
|
||||
|
||||
// UploadVideos 只在使用者确认后逐件执行;未决操作只能查询,不能生成新键重放写入。
|
||||
func (a *App) UploadVideos(productIDs []string) error {
|
||||
func (a *App) UploadVideos(productIDs []string) (uploadErr error) {
|
||||
defer func() {
|
||||
if uploadErr != nil && a.log != nil {
|
||||
a.log.Error("启动视频上传失败:%s", uploadRequestSummary(uploadErr))
|
||||
}
|
||||
}()
|
||||
if a.db == nil {
|
||||
return fmt.Errorf("数据库未就绪,请查看运行日志")
|
||||
}
|
||||
@@ -221,6 +226,19 @@ func videoCode(err error) string {
|
||||
return "VIDEO_REQUEST_FAILED"
|
||||
}
|
||||
|
||||
// 上传入口错误只记稳定字段;尤其不要把原始上游响应、请求地址或凭据写入日志。
|
||||
func uploadRequestSummary(err error) string {
|
||||
var videoErr *erpgo.VideoError
|
||||
if errors.As(err, &videoErr) {
|
||||
return fmt.Sprintf("%s (HTTP %d, requestId=%s)", videoCode(err), videoErr.Status, videoErr.RequestID)
|
||||
}
|
||||
var bridgeErr *erpgo.Error
|
||||
if errors.As(err, &bridgeErr) {
|
||||
return erpgo.LogSummary(err)
|
||||
}
|
||||
return "LOCAL_UPLOAD_ERROR"
|
||||
}
|
||||
|
||||
func safeUploadCode(value string) bool {
|
||||
if len(value) == 0 || len(value) > 64 {
|
||||
return false
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmsp/internal/downloader"
|
||||
@@ -92,3 +93,59 @@ func TestVideoUploadUsesERPGoAndPersistsOutcome(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadPreviewFailureIsLoggedWithoutKey(t *testing.T) {
|
||||
const key = "fictional-secret-key"
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
fmt.Fprint(w, `{"code":401,"errorCode":"API_KEY_INVALID","requestId":"fictional-request"}`)
|
||||
}))
|
||||
defer server.Close()
|
||||
db, err := store.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
if err := db.UpsertProducts([]store.Product{{ID: "internal-1", ItemID: "123"}}, "2026-09-30 00:00:00"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a := NewApp()
|
||||
a.db = db
|
||||
a.cfg.ERPGo.BaseURL, a.cfg.ERPGo.APIKey = server.URL, key
|
||||
a.cfg.Download.VideoDir = t.TempDir()
|
||||
a.probe = func(context.Context, string) (downloader.ProbeResult, error) {
|
||||
return downloader.ProbeResult{Duration: 20, FormatName: "mp4", Width: 640, Height: 480}, nil
|
||||
}
|
||||
dir := filepath.Join(a.cfg.Download.VideoDir, "123")
|
||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "video.mp4"), []byte("fictional-mp4"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := a.GetUploadPreview([]string{"internal-1"}); err == nil {
|
||||
t.Fatal("expected preview failure")
|
||||
}
|
||||
entries := a.GetLogs()
|
||||
if len(entries) != 1 || !strings.Contains(entries[0].Message, "API_KEY_INVALID") || strings.Contains(entries[0].Message, key) {
|
||||
t.Fatalf("wrong log: %+v", entries)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadStartFailureIsLogged(t *testing.T) {
|
||||
a := NewApp()
|
||||
db, err := store.Open(":memory:")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
a.db = db
|
||||
if err := a.UploadVideos([]string{"internal-1"}); err == nil {
|
||||
t.Fatal("expected unconfigured erpgo")
|
||||
}
|
||||
entries := a.GetLogs()
|
||||
if len(entries) != 1 || !strings.Contains(entries[0].Message, "ERPGo_NOT_CONFIGURED") {
|
||||
t.Fatalf("wrong log: %+v", entries)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user