Files
b2b/app/service/emailService/email.go
2026-03-11 09:33:36 +01:00

139 lines
4.6 KiB
Go

package emailService
import (
"bytes"
"context"
"fmt"
"net/smtp"
"strings"
"git.ma-al.com/goc_marek/timetracker/app/config"
"git.ma-al.com/goc_marek/timetracker/app/service/langsService"
"git.ma-al.com/goc_marek/timetracker/app/templ/emails"
"git.ma-al.com/goc_marek/timetracker/app/utils/i18n"
"git.ma-al.com/goc_marek/timetracker/app/view"
)
// EmailService handles sending emails
type EmailService struct {
config *config.EmailConfig
}
// NewEmailService creates a new EmailService instance
func NewEmailService() *EmailService {
return &EmailService{
config: &config.Get().Email,
}
}
// getLangID returns the language ID from the ISO code using the language service
func getLangID(isoCode string) uint {
if isoCode == "" {
isoCode = "en"
}
lang, err := langsService.LangSrv.GetLanguageByISOCode(isoCode)
if err != nil || lang == nil {
return 1 // Default to English (ID 1)
}
return uint(lang.ID)
}
// SendEmail sends an email to the specified recipient
func (s *EmailService) SendEmail(to, subject, body string) error {
if !s.config.Enabled {
return fmt.Errorf("email service is disabled")
}
// Set up authentication
auth := smtp.PlainAuth("", s.config.SMTPUser, s.config.SMTPPassword, s.config.SMTPHost)
// Create email headers
headers := make(map[string]string)
headers["From"] = fmt.Sprintf("%s <%s>", s.config.FromName, s.config.FromEmail)
headers["To"] = to
headers["Subject"] = subject
headers["MIME-Version"] = "1.0"
headers["Content-Type"] = "text/html; charset=utf-8"
// Build email message
var msg strings.Builder
for k, v := range headers {
msg.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
}
msg.WriteString("\r\n")
msg.WriteString(body)
// Send email
addr := fmt.Sprintf("%s:%d", s.config.SMTPHost, s.config.SMTPPort)
if err := smtp.SendMail(addr, auth, s.config.FromEmail, []string{to}, []byte(msg.String())); err != nil {
return fmt.Errorf("failed to send email: %w", err)
}
return nil
}
// SendVerificationEmail sends an email verification email
func (s *EmailService) SendVerificationEmail(to, token, baseURL, lang string) error {
// Use default language if not provided
if lang == "" {
lang = "en"
}
verificationURL := fmt.Sprintf("%s/%s/verify-email?token=%s", baseURL, lang, token)
langID := getLangID(lang)
subject := i18n.T___(langID, "email.email_verification_subject")
body := s.verificationEmailTemplate(to, verificationURL, langID)
return s.SendEmail(to, subject, body)
}
// SendPasswordResetEmail sends a password reset email
func (s *EmailService) SendPasswordResetEmail(to, token, baseURL, lang string) error {
// Use default language if not provided
if lang == "" {
lang = "en"
}
resetURL := fmt.Sprintf("%s/%s/reset-password?token=%s", baseURL, lang, token)
langID := getLangID(lang)
subject := i18n.T___(langID, "email.email_password_reset_subject")
body := s.passwordResetEmailTemplate(to, resetURL, langID)
return s.SendEmail(to, subject, body)
}
// SendNewUserAdminNotification sends an email to admin when a new user completes registration
func (s *EmailService) SendNewUserAdminNotification(userEmail, userName, baseURL string) error {
if s.config.AdminEmail == "" {
return nil // No admin email configured
}
subject := "New User Registration - Repository Assignment Required"
body := s.newUserAdminNotificationTemplate(userEmail, userName, baseURL)
return s.SendEmail(s.config.AdminEmail, subject, body)
}
// verificationEmailTemplate returns the HTML template for email verification
func (s *EmailService) verificationEmailTemplate(name, verificationURL string, langID uint) string {
buf := bytes.Buffer{}
emails.EmailVerificationWrapper(view.EmailLayout[view.EmailVerificationData]{LangID: langID, Data: view.EmailVerificationData{VerificationURL: verificationURL}}).Render(context.Background(), &buf)
return buf.String()
}
// passwordResetEmailTemplate returns the HTML template for password reset
func (s *EmailService) passwordResetEmailTemplate(name, resetURL string, langID uint) string {
buf := bytes.Buffer{}
emails.EmailPasswordResetWrapper(view.EmailLayout[view.EmailPasswordResetData]{LangID: langID, Data: view.EmailPasswordResetData{ResetURL: resetURL}}).Render(context.Background(), &buf)
return buf.String()
}
// newUserAdminNotificationTemplate returns the HTML template for admin notification
func (s *EmailService) newUserAdminNotificationTemplate(userEmail, userName, baseURL string) string {
buf := bytes.Buffer{}
emails.EmailAdminNotificationWrapper(view.EmailLayout[view.EmailAdminNotificationData]{LangID: 2, Data: view.EmailAdminNotificationData{UserEmail: userEmail, UserName: userName, BaseURL: baseURL}}).Render(context.Background(), &buf)
return buf.String()
}