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/langs" "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 := langs.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() }