package logic import ( "context" "errors" "testing" "time" "img_infinite_canvas/internal/domain/design" sharingmodule "img_infinite_canvas/internal/modules/sharing" "img_infinite_canvas/internal/svc" "img_infinite_canvas/internal/types" ) func TestFilterSharedProjectRedactsCanvasOnlyData(t *testing.T) { project := design.Project{ ID: "project-1", UserID: "91cd197b-8255-4172-9981-77391fd38f33", Brief: "private brief", LastThreadID: "thread-1", Messages: []design.Message{{ ID: "message-1", Content: "private chat", CreatedAt: time.Now(), }}, } canvasAccess := sharingmodule.Access{ Permission: sharingmodule.PermissionCanvas, Capabilities: sharingmodule.PermissionCanvas.Capabilities(), } filtered := filterSharedProject(project, canvasAccess) if filtered.UserID != "" || filtered.Brief != "" || filtered.LastThreadID != "" || len(filtered.Messages) != 0 { t.Fatalf("canvas-only response leaked private fields: %+v", filtered) } if project.UserID == "" || len(project.Messages) == 0 { t.Fatal("filter must not mutate the source project") } } func TestSubmitGeneratorTaskRejectsShareProjectMismatch(t *testing.T) { ctx := sharingmodule.ContextWithAccess(context.Background(), sharingmodule.Access{ProjectID: "shared-project"}) logic := NewSubmitGeneratorTaskLogic(ctx, &svc.ServiceContext{}) _, err := logic.SubmitGeneratorTask(&types.GeneratorTaskSubmitRequest{ProjectId: "other-project"}) if !errors.Is(err, sharingmodule.ErrNotFound) { t.Fatalf("expected share project mismatch to be rejected, got %v", err) } } func TestFilterSharedProjectKeepsViewerMessages(t *testing.T) { project := design.Project{ UserID: "91cd197b-8255-4172-9981-77391fd38f33", Messages: []design.Message{{ ID: "message-1", Content: "visible chat", }}, } viewerAccess := sharingmodule.Access{ Permission: sharingmodule.PermissionViewer, Capabilities: sharingmodule.PermissionViewer.Capabilities(), } filtered := filterSharedProject(project, viewerAccess) if filtered.UserID != "" { t.Fatal("shared response must not expose the owner id") } if len(filtered.Messages) != 1 || filtered.Messages[0].Content != "visible chat" { t.Fatalf("viewer should retain chat messages: %+v", filtered.Messages) } } func TestFilterShareMembersRemovesOwnerIdentifiers(t *testing.T) { owner := sharingmodule.Actor{ Authenticated: true, UserID: "91cd197b-8255-4172-9981-77391fd38f33", Email: "owner@example.com", CountryCode: "+86", Phone: "13800138000", } members := []sharingmodule.Member{ {ID: "email", Identifier: "OWNER@EXAMPLE.COM", Permission: sharingmodule.PermissionEditor}, {ID: "phone", Identifier: "+86 138-0013-8000", Permission: sharingmodule.PermissionViewer}, {ID: "other", Identifier: "member@example.com", Permission: sharingmodule.PermissionViewer}, } filtered := filterShareMembers(members, owner) if len(filtered) != 1 || filtered[0].ID != "other" { t.Fatalf("expected only the non-owner member, got %+v", filtered) } }