fix(media,canvas): 对象存储参考素材优先 URL,并同步清理图片引用提示词 (#434)
* fix(media): 对象存储参考素材 - 协议支持 URL 时优先发送签名链接 开启对象存储后,支持 URL 的上游协议优先发送 OSS/COS/七牛/S3 签名链接;必须传字节的协议仍走 Base64 或 multipart。本地资源回退字节,签发失败直接报错,不自动重发生成。 * fix(canvas): 图片引用清理 - 取消引用时同步移除提示词引用
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"net/url"
|
||||
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -735,13 +736,13 @@ func TestHydrateNewAPIChannel1ResourceUsesSignedOSSURL(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
media := providerMedia{StorageKey: "resource:resource-1", DataURL: "data:image/png;base64,old"}
|
||||
if err := svc.hydrateProviderMedia("user-1", &media, true); err != nil {
|
||||
if err := svc.hydrateProviderMedia("user-1", &media, providerMediaHydrationPolicy{requireURL: true}); err != nil {
|
||||
t.Fatalf("hydrateProviderMedia() error = %v", err)
|
||||
}
|
||||
if !strings.HasPrefix(media.URL, "https://private-bucket.oss-cn-test.aliyuncs.com/") || media.DataURL != "" || !strings.Contains(media.URL, "Signature=") {
|
||||
t.Fatalf("media = %#v", media)
|
||||
}
|
||||
if err := svc.hydrateProviderMedia("other-user", &providerMedia{StorageKey: "resource:resource-1"}, true); err == nil {
|
||||
if err := svc.hydrateProviderMedia("other-user", &providerMedia{StorageKey: "resource:resource-1"}, providerMediaHydrationPolicy{requireURL: true}); err == nil {
|
||||
t.Fatal("hydrateProviderMedia() allowed another user's resource")
|
||||
}
|
||||
}
|
||||
@@ -760,7 +761,7 @@ func TestHydrateNewAPIChannel1ResourceUsesSignedLocalURL(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
media := providerMedia{StorageKey: "resource:resource-local"}
|
||||
if err := svc.hydrateProviderMedia("user-1", &media, true); err != nil {
|
||||
if err := svc.hydrateProviderMedia("user-1", &media, providerMediaHydrationPolicy{requireURL: true}); err != nil {
|
||||
t.Fatalf("hydrateProviderMedia() error = %v", err)
|
||||
}
|
||||
if !strings.HasPrefix(media.URL, server.URL+"/api/public/resources/resource-local/file/resource-local.png?") || !strings.Contains(media.URL, "signature=") || media.DataURL != "" {
|
||||
@@ -772,6 +773,51 @@ func TestHydrateNewAPIChannel1ResourceUsesSignedLocalURL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHydratePreferredURLUsesObjectStorageAndFallsBackLocal(t *testing.T) {
|
||||
svc := newResourceTestService(t)
|
||||
settingJSON, _ := json.Marshal(ossSettingValue{
|
||||
Enabled: true, Provider: "aliyun", Endpoint: "https://oss-cn-test.aliyuncs.com", Bucket: "private-bucket",
|
||||
AccessKeyID: "access-id", AccessKeySecret: "secret-value",
|
||||
})
|
||||
if err := svc.repo.SaveSystemSetting(&model.SystemSetting{Key: ossSettingKey, ValueJSON: string(settingJSON)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
objectResource := model.Resource{
|
||||
ID: "resource-oss", UserID: "user-1", Kind: "image", Status: model.ResourceStatusReady,
|
||||
Provider: "aliyun", Endpoint: "https://oss-cn-test.aliyuncs.com", Bucket: "private-bucket",
|
||||
ObjectKey: "users/user-1/image/prefer.png", MimeType: "image/png",
|
||||
}
|
||||
if err := svc.repo.CreateResource(&objectResource); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
media := providerMedia{StorageKey: "resource:resource-oss", DataURL: "data:image/png;base64,old"}
|
||||
if err := svc.hydrateProviderMedia("user-1", &media, providerMediaHydrationPolicy{preferURL: true}); err != nil {
|
||||
t.Fatalf("hydrateProviderMedia(prefer object) error = %v", err)
|
||||
}
|
||||
if !strings.HasPrefix(media.URL, "https://private-bucket.oss-cn-test.aliyuncs.com/") || media.DataURL != "" || !strings.Contains(media.URL, "Signature=") {
|
||||
t.Fatalf("object media = %#v", media)
|
||||
}
|
||||
|
||||
localDir := filepath.Join(svc.dataDir, "resources", "users", "user-1", "image")
|
||||
if err := os.MkdirAll(localDir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(localDir, "local.png"), []byte("png-bytes"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
localResource := model.Resource{ID: "resource-local-bytes", UserID: "user-1", Kind: "image", Status: model.ResourceStatusReady, Provider: "local", ObjectKey: "users/user-1/image/local.png", MimeType: "image/png"}
|
||||
if err := svc.repo.CreateResource(&localResource); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
localMedia := providerMedia{StorageKey: "resource:resource-local-bytes"}
|
||||
if err := svc.hydrateProviderMedia("user-1", &localMedia, providerMediaHydrationPolicy{preferURL: true}); err != nil {
|
||||
t.Fatalf("hydrateProviderMedia(prefer local) error = %v", err)
|
||||
}
|
||||
if localMedia.URL != "" || !strings.HasPrefix(localMedia.DataURL, "data:image/png;base64,") {
|
||||
t.Fatalf("local media = %#v", localMedia)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicResourceSignatureRejectsExpiredAndAlteredLinks(t *testing.T) {
|
||||
svc := newResourceTestService(t)
|
||||
expires := strconv.FormatInt(time.Now().Add(time.Minute).Unix(), 10)
|
||||
|
||||
Reference in New Issue
Block a user