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

View File

@@ -18,59 +18,33 @@ import (
"bytes" "bytes"
"context" "context"
"embed" "embed"
"errors"
"fmt" "fmt"
htmltemplate "html/template" htmltemplate "html/template"
"io/fs"
"mime"
"net/url" "net/url"
"path/filepath"
texttemplate "text/template" texttemplate "text/template"
"time" "time"
"github.com/aws/aws-sdk-go-v2/service/s3"
"go.probo.inc/probo/pkg/baseurl" "go.probo.inc/probo/pkg/baseurl"
"go.probo.inc/probo/pkg/filemanager" "go.probo.inc/probo/pkg/brand"
"go.probo.inc/probo/pkg/filevalidation"
) )
//go:embed dist //go:embed dist
var Templates embed.FS var Templates embed.FS
var (
//go:embed assets
staticAssets embed.FS
staticAssetsValidator = filevalidation.NewValidator(
filevalidation.WithMaxFileSize(5*1024*1024),
filevalidation.WithCategories(
filevalidation.CategoryImage,
filevalidation.CategoryVideo,
),
)
staticAssetsDuration = 7 * 24 * time.Hour
)
type ( type (
Asset struct {
Name string
ObjectKey string
BucketName string
MimeType string
}
PresenterConfig struct { PresenterConfig struct {
APIBaseURL string
BaseURL string BaseURL string
PoweredByLogo Asset PoweredByLogoPath string
SenderCompanyName string SenderCompanyName string
SenderCompanyWebsiteURL string SenderCompanyWebsiteURL string
SenderCompanyLogo Asset SenderCompanyLogoPath string
SenderCompanyHeadquarterAddress string SenderCompanyHeadquarterAddress string
} }
CommonVariables struct { CommonVariables struct {
// Static variables // Static variables
APIBaseURL string
BaseURL string BaseURL string
PoweredByLogoURL string PoweredByLogoURL string
SenderCompanyName string SenderCompanyName string
@@ -83,131 +57,37 @@ type (
} }
Presenter struct { Presenter struct {
fm *filemanager.Service
config PresenterConfig config PresenterConfig
RecipientFullName string RecipientFullName string
} }
) )
func (a *Asset) GetObjectKey() string { func DefaultPresenterConfig(baseURL string) PresenterConfig {
return a.ObjectKey
}
func (a *Asset) GetName() string {
return a.Name
}
func (a *Asset) GetBucketName() string {
return a.BucketName
}
func (a *Asset) GetMimeType() string {
return a.MimeType
}
var _ filemanager.File = (*Asset)(nil)
func DefaultPresenterConfig(staticAssetsBucket string, baseURL string) PresenterConfig {
return PresenterConfig{ return PresenterConfig{
BaseURL: baseURL, APIBaseURL: baseURL, // always API base URL
PoweredByLogo: Asset{ BaseURL: baseURL, // can change to custom domain when needed
Name: "probo-gray-small.png", PoweredByLogoPath: brand.DefaultPoweredByLogoPath,
ObjectKey: "probo-gray-small.png", SenderCompanyName: "Probo",
BucketName: staticAssetsBucket, SenderCompanyWebsiteURL: "https://www.getprobo.com",
MimeType: "image/png", SenderCompanyLogoPath: brand.DefaultSenderCompanyLogoPath,
},
SenderCompanyName: "Probo",
SenderCompanyWebsiteURL: "https://www.getprobo.com",
SenderCompanyLogo: Asset{
Name: "probo.png",
ObjectKey: "probo.png",
BucketName: staticAssetsBucket,
MimeType: "image/png",
},
SenderCompanyHeadquarterAddress: "Probo Inc, 490 Post St, STE 640, San Francisco, CA, 94102, US", SenderCompanyHeadquarterAddress: "Probo Inc, 490 Post St, STE 640, San Francisco, CA, 94102, US",
} }
} }
func NewPresenterFromConfig(fileService *filemanager.Service, cfg PresenterConfig, fullName string) *Presenter { func NewPresenterFromConfig(cfg PresenterConfig, fullName string) *Presenter {
return &Presenter{ return &Presenter{
fm: fileService,
config: cfg, config: cfg,
RecipientFullName: fullName, RecipientFullName: fullName,
} }
} }
func NewPresenter(fileService *filemanager.Service, staticAssetsBucket string, baseURL string, fullName string) *Presenter { func NewPresenter(baseURL string, fullName string) *Presenter {
return NewPresenterFromConfig( return NewPresenterFromConfig(
fileService, DefaultPresenterConfig(baseURL),
DefaultPresenterConfig(staticAssetsBucket, baseURL),
fullName, fullName,
) )
} }
func UploadStaticAssets(ctx context.Context, s3Client *s3.Client, staticAssetsBucket string) error {
subFS, err := fs.Sub(staticAssets, "assets")
if err != nil {
return fmt.Errorf("cannot create subtree file system: %w", err)
}
err = fs.WalkDir(subFS, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
info, err := d.Info()
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return nil
}
return fmt.Errorf("cannot get dir entry info: %w", err)
}
ext := filepath.Ext(info.Name())
mimeType := mime.TypeByExtension(ext)
if err := staticAssetsValidator.Validate(info.Name(), mimeType, info.Size()); err != nil {
return fmt.Errorf("cannot validate file: %w", err)
}
file, err := subFS.Open(path)
if err != nil {
return err
}
defer func() { _ = file.Close() }()
_, err = s3Client.PutObject(
ctx,
&s3.PutObjectInput{
Bucket: new(staticAssetsBucket),
Key: new(path),
Body: file,
Metadata: map[string]string{
"type": "static-email-asset",
},
ContentType: new(mimeType),
CacheControl: new("max-age=3600, public"),
},
)
if err != nil {
return fmt.Errorf("cannot upload file to S3: %w", err)
}
return nil
})
if err != nil {
return fmt.Errorf("cannot generate asset URLs: %w", err)
}
return nil
}
const ( const (
subjectConfirmEmail = "Confirm your email address" subjectConfirmEmail = "Confirm your email address"
subjectPasswordReset = "Reset your password" subjectPasswordReset = "Reset your password"
@@ -255,18 +135,13 @@ var (
mailingListUpdatesTextTemplate = texttemplate.Must(texttemplate.ParseFS(Templates, "dist/mailing-list-updates.txt.tmpl")) mailingListUpdatesTextTemplate = texttemplate.Must(texttemplate.ParseFS(Templates, "dist/mailing-list-updates.txt.tmpl"))
) )
func (p *Presenter) getCommonVariables(ctx context.Context) (*CommonVariables, error) { func (p *Presenter) getCommonVariables() (*CommonVariables, error) {
poweredByLogoURL, err := p.fm.GenerateFileUrl(ctx, &p.config.PoweredByLogo, staticAssetsDuration) apiBaseURL := baseurl.MustParse(p.config.APIBaseURL)
if err != nil { poweredByLogoURL := apiBaseURL.AppendPath(p.config.PoweredByLogoPath).MustString()
return nil, fmt.Errorf("cannot generate probo logo URL: %w", err) senderCompanyLogoURL := apiBaseURL.AppendPath(p.config.SenderCompanyLogoPath).MustString()
}
senderCompanyLogoURL, err := p.fm.GenerateFileUrl(ctx, &p.config.SenderCompanyLogo, staticAssetsDuration)
if err != nil {
return nil, fmt.Errorf("cannot generate sender logo URL: %w", err)
}
return &CommonVariables{ return &CommonVariables{
APIBaseURL: p.config.APIBaseURL,
BaseURL: p.config.BaseURL, BaseURL: p.config.BaseURL,
PoweredByLogoURL: poweredByLogoURL, PoweredByLogoURL: poweredByLogoURL,
SenderCompanyName: p.config.SenderCompanyName, SenderCompanyName: p.config.SenderCompanyName,
@@ -278,7 +153,7 @@ func (p *Presenter) getCommonVariables(ctx context.Context) (*CommonVariables, e
} }
func (p *Presenter) RenderConfirmEmail(ctx context.Context, confirmationURLPath string, confirmationTokenParam string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderConfirmEmail(ctx context.Context, confirmationURLPath string, confirmationTokenParam string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -303,7 +178,7 @@ func (p *Presenter) RenderConfirmEmail(ctx context.Context, confirmationURLPath
} }
func (p *Presenter) RenderPasswordReset(ctx context.Context, resetPasswordURLPath string, resetPasswordToken string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderPasswordReset(ctx context.Context, resetPasswordURLPath string, resetPasswordToken string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -328,7 +203,7 @@ func (p *Presenter) RenderPasswordReset(ctx context.Context, resetPasswordURLPat
} }
func (p *Presenter) RenderInvitation(ctx context.Context, invitationURLPath string, invitationToken string, organizationName string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderInvitation(ctx context.Context, invitationURLPath string, invitationToken string, organizationName string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -361,7 +236,7 @@ func (p *Presenter) RenderDocumentApproval(
organizationName string, organizationName string,
documentName string, documentName string,
) (subject string, textBody string, htmlBody *string, err error) { ) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -394,7 +269,7 @@ func (p *Presenter) RenderDocumentSigning(
signingURLQuery url.Values, signingURLQuery url.Values,
organizationName string, organizationName string,
) (subject string, textBody string, htmlBody *string, err error) { ) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -420,7 +295,7 @@ func (p *Presenter) RenderDocumentSigning(
} }
func (p *Presenter) RenderDocumentExport(ctx context.Context, downloadUrl string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderDocumentExport(ctx context.Context, downloadUrl string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -439,7 +314,7 @@ func (p *Presenter) RenderDocumentExport(ctx context.Context, downloadUrl string
} }
func (p *Presenter) RenderFrameworkExport(ctx context.Context, downloadUrl string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderFrameworkExport(ctx context.Context, downloadUrl string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -458,7 +333,7 @@ func (p *Presenter) RenderFrameworkExport(ctx context.Context, downloadUrl strin
} }
func (p *Presenter) RenderTrustCenterAccess(ctx context.Context, organizationName string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderTrustCenterAccess(ctx context.Context, organizationName string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -481,7 +356,7 @@ func (p *Presenter) RenderTrustCenterDocumentAccessRejected(
fileNames []string, fileNames []string,
organizationName string, organizationName string,
) (subject string, textBody string, htmlBody *string, err error) { ) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -502,7 +377,7 @@ func (p *Presenter) RenderTrustCenterDocumentAccessRejected(
} }
func (p *Presenter) RenderMagicLink(ctx context.Context, magicLinkUrlPath string, tokenString string, tokenDuration time.Duration, organizationName string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderMagicLink(ctx context.Context, magicLinkUrlPath string, tokenString string, tokenDuration time.Duration, organizationName string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -525,7 +400,7 @@ func (p *Presenter) RenderMagicLink(ctx context.Context, magicLinkUrlPath string
} }
func (p *Presenter) RenderElectronicSignatureCertificate(ctx context.Context, signerName string, documentName string, subject string) (textBody string, htmlBody *string, err error) { func (p *Presenter) RenderElectronicSignatureCertificate(ctx context.Context, signerName string, documentName string, subject string) (textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -546,7 +421,7 @@ func (p *Presenter) RenderElectronicSignatureCertificate(ctx context.Context, si
} }
func (p *Presenter) RenderMailingListSubscription(ctx context.Context, organizationName string, confirmURL string, unsubscribeURL string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderMailingListSubscription(ctx context.Context, organizationName string, confirmURL string, unsubscribeURL string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -572,7 +447,7 @@ func (p *Presenter) RenderMailingListSubscription(ctx context.Context, organizat
} }
func (p *Presenter) RenderMailingListUnsubscription(ctx context.Context, organizationName string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderMailingListUnsubscription(ctx context.Context, organizationName string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }
@@ -594,7 +469,7 @@ func (p *Presenter) RenderMailingListUnsubscription(ctx context.Context, organiz
} }
func (p *Presenter) RenderMailingListNews(ctx context.Context, organizationName string, newsTitle string, newsBody string, compliancePageURL string, unsubscribeURL string) (subject string, textBody string, htmlBody *string, err error) { func (p *Presenter) RenderMailingListNews(ctx context.Context, organizationName string, newsTitle string, newsBody string, compliancePageURL string, unsubscribeURL string) (subject string, textBody string, htmlBody *string, err error) {
vars, err := p.getCommonVariables(ctx) vars, err := p.getCommonVariables()
if err != nil { if err != nil {
return "", "", nil, fmt.Errorf("cannot get common variables: %w", err) return "", "", nil, fmt.Errorf("cannot get common variables: %w", err)
} }

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 74 KiB

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) 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) docName := ref.UnrefOrZero(signature.DocumentName)
if docName == "" { if docName == "" {

View File

@@ -464,7 +464,7 @@ func (s *Service) GenerateCertificateFileURL(
return "", err return "", err
} }
url, err := s.fileManager.GenerateFileUrl(ctx, &file, expiresIn) url, err := s.fileManager.GenerateFileURL(ctx, &file, expiresIn)
if err != nil { if err != nil {
return "", fmt.Errorf("cannot generate certificate file URL: %w", err) return "", fmt.Errorf("cannot generate certificate file URL: %w", err)
} }
@@ -501,7 +501,7 @@ func (s *Service) GenerateSignatureFileURL(
return "", err return "", err
} }
url, err := s.fileManager.GenerateFileUrl(ctx, &file, expiresIn) url, err := s.fileManager.GenerateFileURL(ctx, &file, expiresIn)
if err != nil { if err != nil {
return "", fmt.Errorf("cannot generate signature file URL: %w", err) 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 "", 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. // 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. // 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) { 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 return *headOutput.ContentLength, nil
} }
func (s *Service) GenerateFileUrl( func (s *Service) GenerateFileURL(
ctx context.Context, ctx context.Context,
file File, file File,
expiresIn time.Duration, 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) 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) subject, textBody, htmlBody, err := emailPresenter.RenderConfirmEmail(ctx, "/auth/verify-email", confirmationToken)
if err != nil { if err != nil {

View File

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

View File

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

View File

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

View File

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

View File

@@ -722,7 +722,7 @@ func (s *Service) CreateUpdateEmails(
return fmt.Errorf("cannot generate unsubscribe URL: %w", err) 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) RenderMailingListNews(ctx, orgName, updateTitle, updateBody, compliancePageURL, unsubscribeURL)
if err != nil { if err != nil {
return fmt.Errorf("cannot render mailing list update email: %w", err) 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) 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) RenderMailingListSubscription(ctx, orgName, confirmURL, unsubscribeURL)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot render subscription confirmation email: %w", err) 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) 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) RenderMailingListUnsubscription(ctx, orgName)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot render unsubscription email: %w", err) 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)) approvalEmails := make(coredata.Emails, 0, len(profiles))
for _, profile := range 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 ( var (
emailLinkURLPath = approvalURLPath emailLinkURLPath = approvalURLPath

View File

@@ -743,7 +743,7 @@ func (s *DocumentService) SendSigningNotifications(
} }
for _, signatory := range signatories { 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 ( var (
employeeDocumentsURLPath = "/organizations/" + organizationID.String() + "/employee" employeeDocumentsURLPath = "/organizations/" + organizationID.String() + "/employee"
@@ -2629,7 +2629,7 @@ func (s *DocumentService) SendExportEmail(
return fmt.Errorf("cannot generate download URL: %w", err) 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( subject, textBody, htmlBody, err := emailPresenter.RenderDocumentExport(
ctx, ctx,

View File

@@ -202,7 +202,7 @@ func (s FileService) GenerateFileURL(
return "", fmt.Errorf("cannot get file: %w", err) 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 { if err != nil {
return "", fmt.Errorf("cannot generate file URL: %w", err) 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) 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( subject, textBody, htmlBody, err := emailPresenter.RenderFrameworkExport(
ctx, ctx,
@@ -866,7 +866,7 @@ func (s FrameworkService) GenerateLightLogoURL(
return nil, nil return nil, nil
} }
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn) presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err) return nil, fmt.Errorf("cannot generate file URL: %w", err)
} }
@@ -908,7 +908,7 @@ func (s FrameworkService) GenerateDarkLogoURL(
return nil, nil return nil, nil
} }
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn) presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err) return nil, fmt.Errorf("cannot generate file URL: %w", err)
} }

View File

@@ -450,7 +450,7 @@ func (s OrganizationService) GenerateLogoURL(
return nil, nil return nil, nil
} }
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn) presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err) return nil, fmt.Errorf("cannot generate file URL: %w", err)
} }
@@ -492,7 +492,7 @@ func (s OrganizationService) GenerateHorizontalLogoURL(
return nil, nil return nil, nil
} }
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn) presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err) 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) 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) subject, textBody, htmlBody, err := emailPresenter.RenderTrustCenterAccess(ctx, organization.Name)
if err != nil { if err != nil {

View File

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

View File

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

View File

@@ -41,7 +41,6 @@ import (
"go.gearno.de/kit/worker" "go.gearno.de/kit/worker"
"go.gearno.de/x/ref" "go.gearno.de/x/ref"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"go.probo.inc/probo/packages/emails"
"go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/accessreview"
"go.probo.inc/probo/pkg/agentrun" "go.probo.inc/probo/pkg/agentrun"
"go.probo.inc/probo/pkg/awsconfig" "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( iamService, err := iam.NewService(
ctx, ctx,
pgClient, pgClient,

View File

@@ -16,11 +16,14 @@ package files_v1
import ( import (
"errors" "errors"
"fmt"
"io/fs"
"net/http" "net/http"
"time" "time"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"go.gearno.de/kit/log" "go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/brand"
"go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/file" "go.probo.inc/probo/pkg/file"
"go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/gid"
@@ -57,6 +60,7 @@ func NewMux(
r := chi.NewRouter() r := chi.NewRouter()
r.Get("/static/{file}", h.handleGetStaticFile)
r.Get("/public/{fileID}", h.handleGetPublicFile) r.Get("/public/{fileID}", h.handleGetPublicFile)
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
@@ -70,6 +74,17 @@ func NewMux(
return r 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) { func (h *Handler) handleGetPublicFile(w http.ResponseWriter, r *http.Request) {
fileIDStr := chi.URLParam(r, "fileID") fileIDStr := chi.URLParam(r, "fileID")

View File

@@ -85,7 +85,7 @@ func (s FrameworkService) GenerateLightLogoURL(
return nil, nil return nil, nil
} }
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn) presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err) return nil, fmt.Errorf("cannot generate file URL: %w", err)
} }
@@ -128,7 +128,7 @@ func (s FrameworkService) GenerateDarkLogoURL(
return nil, nil return nil, nil
} }
presignedURL, err := s.svc.fileManager.GenerateFileUrl(ctx, file, expiresIn) presignedURL, err := s.svc.fileManager.GenerateFileURL(ctx, file, expiresIn)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot generate file URL: %w", err) 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) 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) subject, textBody, htmlBody, err := emailPresenter.RenderTrustCenterAccess(ctx, organization.Name)
if err != nil { if err != nil {
@@ -604,7 +604,7 @@ func (s *TrustCenterAccessService) sendDocumentAccessRejectedEmail(
return fmt.Errorf("cannot get compliance page email presenter config: %w", err) 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( subject, textBody, htmlBody, err := emailPresenter.RenderTrustCenterDocumentAccessRejected(
ctx, ctx,

View File

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