Migrate Connect org logos to File type

Replace Organization.logoUrl and horizontalLogoUrl with nested File
objects whose downloadUrl points at /api/files/v1/public/{id}, matching
the Console migration.

Org logos are FileVisibilityPublic and served without HTTP auth, so
Connect File.downloadUrl is built eagerly in NewFile with no field-level
authorize. Logo loading moves to iam.OrganizationService.LogoFile and
HorizontalLogoFile; the old URL generators are removed.

Sync IAM Relay components and n8n organization operations. Add an e2e
test for Connect multipart logo upload and ExecuteConnectWithFile.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
Ludovic Vielle
2026-06-10 16:19:45 +02:00
parent c7e2fc209f
commit e06f3e0520
17 changed files with 315 additions and 84 deletions

View File

@@ -1372,18 +1372,17 @@ func (s *OrganizationService) GetOrganizationForMembership(ctx context.Context,
return organization, nil
}
func (s OrganizationService) GenerateLogoURL(
func (s OrganizationService) LogoFile(
ctx context.Context,
organizationID gid.GID,
expiresIn time.Duration,
) (*string, error) {
) (*coredata.File, error) {
var (
errNoLogoFile = errors.New("no logo file found")
scope = coredata.NewScopeFromObjectID(organizationID)
file = &coredata.File{}
)
err := s.pg.WithConn(
if err := s.pg.WithConn(
ctx,
func(ctx context.Context, conn pg.Querier) error {
organization := &coredata.Organization{}
@@ -1401,35 +1400,28 @@ func (s OrganizationService) GenerateLogoURL(
return nil
},
)
if err == errNoLogoFile {
return nil, nil
); err != nil {
if errors.Is(err, errNoLogoFile) {
return nil, nil
}
return nil, fmt.Errorf("cannot load logo file: %w", err)
}
if err != nil {
return nil, fmt.Errorf("cannot generate logo URL: %w", err)
}
downloadURL, err := s.fm.BuildDownloadURL(file)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
return &downloadURL, nil
return file, nil
}
func (s OrganizationService) GenerateHorizontalLogoURL(
func (s OrganizationService) HorizontalLogoFile(
ctx context.Context,
organizationID gid.GID,
expiresIn time.Duration,
) (*string, error) {
) (*coredata.File, error) {
var (
errNoLogoFile = errors.New("no logo file found")
scope = coredata.NewScopeFromObjectID(organizationID)
file = &coredata.File{}
)
err := s.pg.WithConn(
if err := s.pg.WithConn(
ctx,
func(ctx context.Context, conn pg.Querier) error {
organization := &coredata.Organization{}
@@ -1447,21 +1439,15 @@ func (s OrganizationService) GenerateHorizontalLogoURL(
return nil
},
)
if err == errNoLogoFile {
return nil, nil
); err != nil {
if errors.Is(err, errNoLogoFile) {
return nil, nil
}
return nil, fmt.Errorf("cannot load horizontal logo file: %w", err)
}
if err != nil {
return nil, err
}
downloadURL, err := s.fm.BuildDownloadURL(file)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
return &downloadURL, nil
return file, nil
}
func (s OrganizationService) DeleteSAMLConfiguration(