wg-portal/internal/app/mail/manager.go

146 lines
3.5 KiB
Go
Raw Normal View History

package mail
import (
"context"
"fmt"
2025-02-28 08:29:40 +01:00
"io"
"log/slog"
2025-02-28 08:29:40 +01:00
"github.com/h44z/wg-portal/internal/config"
"github.com/h44z/wg-portal/internal/domain"
)
type Manager struct {
cfg *config.Config
tplHandler *TemplateHandler
mailer Mailer
configFiles ConfigFileManager
users UserDatabaseRepo
wg WireguardDatabaseRepo
}
2025-02-28 08:29:40 +01:00
func NewMailManager(
cfg *config.Config,
mailer Mailer,
configFiles ConfigFileManager,
users UserDatabaseRepo,
wg WireguardDatabaseRepo,
) (*Manager, error) {
tplHandler, err := newTemplateHandler(cfg.Web.ExternalUrl)
if err != nil {
return nil, fmt.Errorf("failed to initialize template handler: %w", err)
}
m := &Manager{
cfg: cfg,
tplHandler: tplHandler,
mailer: mailer,
configFiles: configFiles,
users: users,
wg: wg,
}
return m, nil
}
func (m Manager) SendPeerEmail(ctx context.Context, linkOnly bool, peers ...domain.PeerIdentifier) error {
for _, peerId := range peers {
peer, err := m.wg.GetPeer(ctx, peerId)
if err != nil {
return fmt.Errorf("failed to fetch peer %s: %w", peerId, err)
}
2024-01-31 21:14:36 +01:00
if err := domain.ValidateUserAccessRights(ctx, peer.UserIdentifier); err != nil {
return err
}
if peer.UserIdentifier == "" {
slog.Debug("skipping peer email",
"peer", peerId,
"reason", "no user linked")
continue
}
user, err := m.users.GetUser(ctx, peer.UserIdentifier)
if err != nil {
slog.Debug("skipping peer email",
"peer", peerId,
"reason", "unable to fetch user",
"error", err)
continue
}
if user.Email == "" {
slog.Debug("skipping peer email",
"peer", peerId,
"reason", "user has no mail address")
continue
}
err = m.sendPeerEmail(ctx, linkOnly, user, peer)
if err != nil {
return fmt.Errorf("failed to send peer email for %s: %w", peerId, err)
}
}
return nil
}
func (m Manager) sendPeerEmail(ctx context.Context, linkOnly bool, user *domain.User, peer *domain.Peer) error {
qrName := "WireGuardQRCode.png"
configName := peer.GetConfigFileName()
var (
txtMail, htmlMail io.Reader
err error
mailOptions domain.MailOptions
)
if linkOnly {
txtMail, htmlMail, err = m.tplHandler.GetConfigMail(user, "deep link TBD")
if err != nil {
return fmt.Errorf("failed to get mail body: %w", err)
}
} else {
peerConfig, err := m.configFiles.GetPeerConfig(ctx, peer.Identifier)
if err != nil {
return fmt.Errorf("failed to fetch peer config for %s: %w", peer.Identifier, err)
}
peerConfigQr, err := m.configFiles.GetPeerConfigQrCode(ctx, peer.Identifier)
if err != nil {
return fmt.Errorf("failed to fetch peer config QR code for %s: %w", peer.Identifier, err)
}
txtMail, htmlMail, err = m.tplHandler.GetConfigMailWithAttachment(user, configName, qrName)
if err != nil {
return fmt.Errorf("failed to get full mail body: %w", err)
}
mailOptions.Attachments = append(mailOptions.Attachments, domain.MailAttachment{
Name: configName,
ContentType: "text/plain",
Data: peerConfig,
Embedded: false,
})
mailOptions.Attachments = append(mailOptions.Attachments, domain.MailAttachment{
Name: qrName,
ContentType: "image/png",
Data: peerConfigQr,
Embedded: true,
})
}
txtMailStr, _ := io.ReadAll(txtMail)
htmlMailStr, _ := io.ReadAll(htmlMail)
mailOptions.HtmlBody = string(htmlMailStr)
err = m.mailer.Send(ctx, "WireGuard VPN Configuration", string(txtMailStr), []string{user.Email}, &mailOptions)
if err != nil {
return fmt.Errorf("failed to send mail: %w", err)
}
return nil
}