Serve brand assets as static files via /api/files/v1/static instead of S3

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
Ludovic Vielle
2026-06-09 16:43:59 +02:00
parent c6c35a542e
commit 60435f277b
27 changed files with 125 additions and 241 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
pkg/brand/assets/probo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

25
pkg/brand/brand.go Normal file
View File

@@ -0,0 +1,25 @@
package brand
import (
"embed"
"io/fs"
)
var (
//go:embed assets
staticAssets embed.FS
Assets fs.FS
DefaultPoweredByLogoPath string = "/api/files/v1/static/probo-gray-small.png"
DefaultSenderCompanyLogoPath string = "/api/files/v1/static/probo.png"
)
func init() {
var err error
Assets, err = fs.Sub(staticAssets, "assets")
if err != nil {
panic(err)
}
}

View File

@@ -264,7 +264,7 @@ func (h *completionCertificateHandler) generateCertificate(
return nil, nil, fmt.Errorf("cannot resolve presenter config: %w", err)
}
emailPresenter := emails.NewPresenterFromConfig(h.fileManager, presenterCfg, ref.UnrefOrZero(signature.SignerFullName))
emailPresenter := emails.NewPresenterFromConfig(presenterCfg, ref.UnrefOrZero(signature.SignerFullName))
docName := ref.UnrefOrZero(signature.DocumentName)
if docName == "" {

View File

@@ -464,7 +464,7 @@ func (s *Service) GenerateCertificateFileURL(
return "", err
}
url, err := s.fileManager.GenerateFileUrl(ctx, &file, expiresIn)
url, err := s.fileManager.GenerateFileURL(ctx, &file, expiresIn)
if err != nil {
return "", fmt.Errorf("cannot generate certificate file URL: %w", err)
}
@@ -501,7 +501,7 @@ func (s *Service) GenerateSignatureFileURL(
return "", err
}
url, err := s.fileManager.GenerateFileUrl(ctx, &file, expiresIn)
url, err := s.fileManager.GenerateFileURL(ctx, &file, expiresIn)
if err != nil {
return "", fmt.Errorf("cannot generate signature file URL: %w", err)
}

View File

@@ -82,11 +82,11 @@ func (s *Service) GeneratePublicPresignedURL(ctx context.Context, fileID gid.GID
return "", err
}
return s.fileManager.GenerateFileUrl(ctx, file, expiresIn)
return s.fileManager.GenerateFileURL(ctx, file, expiresIn)
}
// GeneratePresignedURL returns a short-lived S3 presigned URL for an already-loaded file.
// Used by the authenticated /api/files/v1/{id} HTTP handler to avoid a second DB round-trip.
func (s *Service) GeneratePresignedURL(ctx context.Context, file *coredata.File, expiresIn time.Duration) (string, error) {
return s.fileManager.GenerateFileUrl(ctx, file, expiresIn)
return s.fileManager.GenerateFileURL(ctx, file, expiresIn)
}

View File

@@ -152,7 +152,7 @@ func (s *Service) PutFile(
return *headOutput.ContentLength, nil
}
func (s *Service) GenerateFileUrl(
func (s *Service) GenerateFileURL(
ctx context.Context,
file File,
expiresIn time.Duration,

View File

@@ -129,7 +129,7 @@ func (s AccountService) ChangeEmail(ctx context.Context, identityID gid.GID, req
return fmt.Errorf("cannot update identity: %w", err)
}
emailPresenter := emails.NewPresenter(s.fm, s.bucket, s.baseURL, identity.FullName)
emailPresenter := emails.NewPresenter(s.baseURL, identity.FullName)
subject, textBody, htmlBody, err := emailPresenter.RenderConfirmEmail(ctx, "/auth/verify-email", confirmationToken)
if err != nil {

View File

@@ -314,7 +314,7 @@ func (s AuthService) SendPasswordResetInstructionByEmail(
return fmt.Errorf("cannot load identity: %w", err)
}
emailPresenter := emails.NewPresenter(s.fm, s.bucket, s.baseURL, identity.FullName)
emailPresenter := emails.NewPresenter(s.baseURL, identity.FullName)
subject, textBody, htmlBody, err := emailPresenter.RenderPasswordReset(
ctx,
@@ -387,7 +387,7 @@ func (s AuthService) CreateIdentityWithPassword(
return nil, nil, fmt.Errorf("cannot generate confirmation token: %w", err)
}
emailPresenter := emails.NewPresenter(s.fm, s.bucket, s.baseURL, req.FullName)
emailPresenter := emails.NewPresenter(s.baseURL, req.FullName)
subject, textBody, htmlBody, err := emailPresenter.RenderConfirmEmail(ctx, "/auth/verify-email", confirmationToken)
if err != nil {
@@ -594,7 +594,7 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques
return fmt.Errorf("cannot load organization: %w", err)
}
emailPresenterCfg := emails.DefaultPresenterConfig(s.bucket, s.baseURL)
emailPresenterCfg := emails.DefaultPresenterConfig(s.baseURL)
if req.CompliancePageID != nil {
var err error
@@ -605,7 +605,7 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques
}
}
emailPresenter := emails.NewPresenterFromConfig(s.fm, emailPresenterCfg, fullName)
emailPresenter := emails.NewPresenterFromConfig(emailPresenterCfg, fullName)
subject, textBody, htmlBody, err := emailPresenter.RenderMagicLink(
ctx,

View File

@@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"net/url"
"path/filepath"
"time"
"go.gearno.de/kit/pg"
@@ -77,7 +78,7 @@ func (s *CompliancePageService) GenerateLogoURL(
return nil, nil
}
presignedURL, err := s.fm.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.fm.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -91,7 +92,7 @@ func (s *CompliancePageService) EmailPresenterConfig(ctx context.Context, compli
organization = &coredata.Organization{}
customDomain *coredata.CustomDomain
logoFile = &coredata.File{}
emailPresenterCfg = emails.DefaultPresenterConfig(s.bucket, s.baseURL)
emailPresenterCfg = emails.DefaultPresenterConfig(s.baseURL)
)
scope := coredata.NewScopeFromObjectID(compliancePageID)
@@ -152,14 +153,7 @@ func (s *CompliancePageService) EmailPresenterConfig(ctx context.Context, compli
}
// If logo exists, then we will brand the emails with the org as a sender
emailPresenterCfg.SenderCompanyLogo = emails.Asset{
Name: logoFile.FileName,
ObjectKey: logoFile.FileKey,
BucketName: logoFile.BucketName,
MimeType: logoFile.MimeType,
}
emailPresenterCfg.SenderCompanyLogoPath = filepath.Join("/api/files/v1/public/", logoFile.ID.String())
emailPresenterCfg.SenderCompanyName = organization.Name
if organization.WebsiteURL != nil {

View File

@@ -514,7 +514,7 @@ func (s *OrganizationService) InviteUser(
return fmt.Errorf("cannot generate invitation token: %w", err)
}
emailPresenter := emails.NewPresenter(s.fm, s.bucket, s.baseURL, profile.FullName)
emailPresenter := emails.NewPresenter(s.baseURL, profile.FullName)
subject, textBody, htmlBody, err := emailPresenter.RenderInvitation(
ctx,
@@ -1409,7 +1409,7 @@ func (s OrganizationService) GenerateLogoURL(
return nil, fmt.Errorf("cannot generate logo URL: %w", err)
}
presignedURL, err := s.fm.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.fm.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -1455,7 +1455,7 @@ func (s OrganizationService) GenerateHorizontalLogoURL(
return nil, err
}
presignedURL, err := s.fm.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.fm.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}

View File

@@ -18,6 +18,7 @@ import (
"context"
"errors"
"fmt"
"path/filepath"
"go.gearno.de/kit/pg"
"go.probo.inc/probo/packages/emails"
@@ -60,7 +61,7 @@ func (s *Service) mailingListEmailConfig(
organization = &coredata.Organization{}
customDomain *coredata.CustomDomain
logoFile = &coredata.File{}
defaultCfg = emails.DefaultPresenterConfig(s.bucket, s.apiBaseURL.String())
defaultCfg = emails.DefaultPresenterConfig(s.apiBaseURL.String())
)
scope := coredata.NewScopeFromObjectID(mailingListID)
@@ -128,7 +129,7 @@ func (s *Service) presenterConfigFromTrustCenter(
customDomain *coredata.CustomDomain,
logoFile *coredata.File,
) (emails.PresenterConfig, string, error) {
cfg := emails.DefaultPresenterConfig(s.bucket, s.apiBaseURL.String())
cfg := emails.DefaultPresenterConfig(s.apiBaseURL.String())
compliancePageBase := s.apiBaseURL.WithPath("/trust/" + compliancePage.ID.String())
@@ -149,12 +150,7 @@ func (s *Service) presenterConfigFromTrustCenter(
cfg.BaseURL = compliancePageURL
if compliancePage.LogoFileID != nil && logoFile != nil && logoFile.FileKey != "" {
cfg.SenderCompanyLogo = emails.Asset{
Name: logoFile.FileName,
ObjectKey: logoFile.FileKey,
BucketName: logoFile.BucketName,
MimeType: logoFile.MimeType,
}
cfg.SenderCompanyLogoPath = filepath.Join("/api/files/v1/public/", logoFile.ID.String())
cfg.SenderCompanyName = organization.Name
if organization.WebsiteURL != nil {

View File

@@ -722,7 +722,7 @@ func (s *Service) CreateUpdateEmails(
return fmt.Errorf("cannot generate unsubscribe URL: %w", err)
}
subject, textBody, htmlBody, err := emails.NewPresenterFromConfig(s.fm, presenterCfg, sub.FullName).
subject, textBody, htmlBody, err := emails.NewPresenterFromConfig(presenterCfg, sub.FullName).
RenderMailingListNews(ctx, orgName, updateTitle, updateBody, compliancePageURL, unsubscribeURL)
if err != nil {
return fmt.Errorf("cannot render mailing list update email: %w", err)
@@ -776,7 +776,7 @@ func (s *Service) buildConfirmationMail(
return nil, fmt.Errorf("cannot get subscription confirmation email config: %w", err)
}
subject, textBody, htmlBody, err := emails.NewPresenterFromConfig(s.fm, presenterCfg, fullName).
subject, textBody, htmlBody, err := emails.NewPresenterFromConfig(presenterCfg, fullName).
RenderMailingListSubscription(ctx, orgName, confirmURL, unsubscribeURL)
if err != nil {
return nil, fmt.Errorf("cannot render subscription confirmation email: %w", err)
@@ -807,7 +807,7 @@ func (s *Service) buildUnsubscriptionMail(
return nil, fmt.Errorf("cannot get unsubscription email config: %w", err)
}
subject, textBody, htmlBody, err := emails.NewPresenterFromConfig(s.fm, presenterCfg, fullName).
subject, textBody, htmlBody, err := emails.NewPresenterFromConfig(presenterCfg, fullName).
RenderMailingListUnsubscription(ctx, orgName)
if err != nil {
return nil, fmt.Errorf("cannot render unsubscription email: %w", err)

View File

@@ -820,7 +820,7 @@ func (s *DocumentApprovalService) sendApprovalEmails(
approvalEmails := make(coredata.Emails, 0, len(profiles))
for _, profile := range profiles {
emailPresenter := emails.NewPresenter(s.svc.fileManager, s.svc.bucket, s.svc.baseURL, profile.FullName)
emailPresenter := emails.NewPresenter(s.svc.baseURL, profile.FullName)
var (
emailLinkURLPath = approvalURLPath

View File

@@ -743,7 +743,7 @@ func (s *DocumentService) SendSigningNotifications(
}
for _, signatory := range signatories {
emailPresenter := emails.NewPresenter(s.svc.fileManager, s.svc.bucket, s.svc.baseURL, signatory.FullName)
emailPresenter := emails.NewPresenter(s.svc.baseURL, signatory.FullName)
var (
employeeDocumentsURLPath = "/organizations/" + organizationID.String() + "/employee"
@@ -2629,7 +2629,7 @@ func (s *DocumentService) SendExportEmail(
return fmt.Errorf("cannot generate download URL: %w", err)
}
emailPresenter := emails.NewPresenter(s.svc.fileManager, s.svc.bucket, s.svc.baseURL, recipientName)
emailPresenter := emails.NewPresenter(s.svc.baseURL, recipientName)
subject, textBody, htmlBody, err := emailPresenter.RenderDocumentExport(
ctx,

View File

@@ -202,7 +202,7 @@ func (s FileService) GenerateFileURL(
return "", fmt.Errorf("cannot get file: %w", err)
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return "", fmt.Errorf("cannot generate file URL: %w", err)
}

View File

@@ -676,7 +676,7 @@ func (s FrameworkService) SendExportEmail(
return fmt.Errorf("cannot generate download URL: %w", err)
}
emailPresenter := emails.NewPresenter(s.svc.fileManager, s.svc.bucket, s.svc.baseURL, recipientName)
emailPresenter := emails.NewPresenter(s.svc.baseURL, recipientName)
subject, textBody, htmlBody, err := emailPresenter.RenderFrameworkExport(
ctx,
@@ -866,7 +866,7 @@ func (s FrameworkService) GenerateLightLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -908,7 +908,7 @@ func (s FrameworkService) GenerateDarkLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}

View File

@@ -450,7 +450,7 @@ func (s OrganizationService) GenerateLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -492,7 +492,7 @@ func (s OrganizationService) GenerateHorizontalLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}

View File

@@ -364,7 +364,7 @@ func (s TrustCenterAccessService) sendAccessEmail(ctx context.Context, scope cor
return fmt.Errorf("cannot get compliance page email presenter config: %w", err)
}
emailPresenter := emails.NewPresenterFromConfig(s.svc.fileManager, emailPresenterCfg, profile.FullName)
emailPresenter := emails.NewPresenterFromConfig(emailPresenterCfg, profile.FullName)
subject, textBody, htmlBody, err := emailPresenter.RenderTrustCenterAccess(ctx, organization.Name)
if err != nil {

View File

@@ -313,7 +313,7 @@ func (s TrustCenterFileService) GenerateFileURL(
return "", err
}
fileURL, err := s.svc.fileManager.GenerateFileUrl(ctx, storedFile, duration)
fileURL, err := s.svc.fileManager.GenerateFileURL(ctx, storedFile, duration)
if err != nil {
return "", fmt.Errorf("cannot generate file URL: %w", err)
}

View File

@@ -500,7 +500,7 @@ func (s TrustCenterService) GenerateNDAFileURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -546,7 +546,7 @@ func (s TrustCenterService) GenerateLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -592,7 +592,7 @@ func (s TrustCenterService) GenerateDarkLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -606,7 +606,7 @@ func (s *TrustCenterService) EmailPresenterConfig(ctx context.Context, scope cor
organization = &coredata.Organization{}
customDomain *coredata.CustomDomain
logoFile = &coredata.File{}
emailPresenterCfg = emails.DefaultPresenterConfig(s.svc.bucket, s.svc.baseURL)
emailPresenterCfg = emails.DefaultPresenterConfig(s.svc.baseURL)
)
err := s.svc.pg.WithConn(
@@ -664,13 +664,7 @@ func (s *TrustCenterService) EmailPresenterConfig(ctx context.Context, scope cor
return emailPresenterCfg, nil
}
emailPresenterCfg.SenderCompanyLogo = emails.Asset{
Name: logoFile.FileName,
ObjectKey: logoFile.FileKey,
BucketName: logoFile.BucketName,
MimeType: logoFile.MimeType,
}
emailPresenterCfg.SenderCompanyLogoPath = filepath.Join("/api/files/v1/public/", logoFile.ID.String())
emailPresenterCfg.SenderCompanyName = organization.Name
if organization.WebsiteURL != nil {

View File

@@ -41,7 +41,6 @@ import (
"go.gearno.de/kit/worker"
"go.gearno.de/x/ref"
"go.opentelemetry.io/otel/trace"
"go.probo.inc/probo/packages/emails"
"go.probo.inc/probo/pkg/accessreview"
"go.probo.inc/probo/pkg/agentrun"
"go.probo.inc/probo/pkg/awsconfig"
@@ -436,14 +435,6 @@ func (impl *Implm) Run(
}
}
if err := emails.UploadStaticAssets(
ctx,
s3Client,
impl.cfg.AWS.Bucket,
); err != nil {
return fmt.Errorf("cannot upload email static assets: %w", err)
}
iamService, err := iam.NewService(
ctx,
pgClient,

View File

@@ -16,11 +16,14 @@ package files_v1
import (
"errors"
"fmt"
"io/fs"
"net/http"
"time"
"github.com/go-chi/chi/v5"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/brand"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/file"
"go.probo.inc/probo/pkg/gid"
@@ -57,6 +60,7 @@ func NewMux(
r := chi.NewRouter()
r.Get("/static/{file}", h.handleGetStaticFile)
r.Get("/public/{fileID}", h.handleGetPublicFile)
r.Group(func(r chi.Router) {
@@ -70,6 +74,17 @@ func NewMux(
return r
}
func (h *Handler) handleGetStaticFile(w http.ResponseWriter, r *http.Request) {
file := chi.URLParam(r, "file")
if _, statErr := fs.Stat(brand.Assets, file); statErr == nil {
http.ServeFileFS(w, r, brand.Assets, file)
return
}
jsonutil.RenderNotFound(w, fmt.Errorf("file not found"))
}
func (h *Handler) handleGetPublicFile(w http.ResponseWriter, r *http.Request) {
fileIDStr := chi.URLParam(r, "fileID")

View File

@@ -85,7 +85,7 @@ func (s FrameworkService) GenerateLightLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -128,7 +128,7 @@ func (s FrameworkService) GenerateDarkLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}

View File

@@ -457,7 +457,7 @@ func (s *TrustCenterAccessService) sendAccessEmail(
return fmt.Errorf("cannot get compliance page email presenter config: %w", err)
}
emailPresenter := emails.NewPresenterFromConfig(s.svc.fileManager, emailPresenterCfg, profile.FullName)
emailPresenter := emails.NewPresenterFromConfig(emailPresenterCfg, profile.FullName)
subject, textBody, htmlBody, err := emailPresenter.RenderTrustCenterAccess(ctx, organization.Name)
if err != nil {
@@ -604,7 +604,7 @@ func (s *TrustCenterAccessService) sendDocumentAccessRejectedEmail(
return fmt.Errorf("cannot get compliance page email presenter config: %w", err)
}
emailPresenter := emails.NewPresenterFromConfig(s.svc.fileManager, emailPresenterCfg, profile.FullName)
emailPresenter := emails.NewPresenterFromConfig(emailPresenterCfg, profile.FullName)
subject, textBody, htmlBody, err := emailPresenter.RenderTrustCenterDocumentAccessRejected(
ctx,

View File

@@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"net/url"
"path/filepath"
"time"
"go.gearno.de/kit/pg"
@@ -147,7 +148,7 @@ func (s TrustCenterService) GenerateNDAFileURL(
return "", err
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return "", fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -194,7 +195,7 @@ func (s TrustCenterService) GenerateLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -241,7 +242,7 @@ func (s TrustCenterService) GenerateDarkLogoURL(
return nil, nil
}
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn)
presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -259,7 +260,7 @@ func (s *TrustCenterService) EmailPresenterConfig(
organization = &coredata.Organization{}
customDomain *coredata.CustomDomain
logoFile = &coredata.File{}
emailPresenterCfg = emails.DefaultPresenterConfig(s.svc.bucket, s.svc.baseURL)
emailPresenterCfg = emails.DefaultPresenterConfig(s.svc.baseURL)
)
err := s.svc.pg.WithConn(
@@ -318,14 +319,7 @@ func (s *TrustCenterService) EmailPresenterConfig(
}
// If logo exists, then we will brand the emails with the org as a sender
emailPresenterCfg.SenderCompanyLogo = emails.Asset{
Name: logoFile.FileName,
ObjectKey: logoFile.FileKey,
BucketName: logoFile.BucketName,
MimeType: logoFile.MimeType,
}
emailPresenterCfg.SenderCompanyLogoPath = filepath.Join("/api/files/v1/public/", logoFile.ID.String())
emailPresenterCfg.SenderCompanyName = organization.Name
if organization.WebsiteURL != nil {