Add Email Testing Functionality to Admin Tools

- Introduced a new section in the admin tools for testing email configurations.
- Added a form to send test emails, including recipient, subject, and message fields.
- Implemented backend logic to handle test email requests and send emails using the configured SMTP server.
- Created a toast notification component to display success or failure messages for email tests.
- Updated routes to include a new endpoint for handling test email submissions.
This commit is contained in:
StarFleetCPTN
2025-03-20 18:11:57 -07:00
parent 1a1df435de
commit d6bd471eb0
4 changed files with 407 additions and 5 deletions
+179
View File
@@ -270,3 +270,182 @@ func (s *Service) sendEmail(toEmail, subject, htmlContent string) error {
return client.Quit()
}
}
// SendTestEmail sends a test email to verify email configuration
func (s *Service) SendTestEmail(toEmail, subject, message string) error {
if !s.Config.Email.Enabled {
return fmt.Errorf("email service is disabled")
}
// Use default subject if not provided
if subject == "" {
subject = "Test Email from GoMFT"
}
// Use default message if not provided
if message == "" {
message = "This is a test email from GoMFT to verify the email configuration is working correctly."
}
// Create email data for template
data := map[string]interface{}{
"Subject": subject,
"Message": message,
"AppName": "GoMFT",
"Year": time.Now().Year(),
"SMTPServer": s.Config.Email.Host,
"SMTPPort": s.Config.Email.Port,
"FromEmail": s.Config.Email.FromEmail,
"CurrentTime": time.Now().Format(time.RFC1123Z),
}
// Generate email content
htmlContent, err := s.generateTestEmailHTML(data)
if err != nil {
return err
}
// Send the email
return s.sendEmail(toEmail, subject, htmlContent)
}
// generateTestEmailHTML generates the HTML content for test emails
func (s *Service) generateTestEmailHTML(data map[string]interface{}) (string, error) {
// HTML template for test email
tmpl, err := template.New("testEmail").Parse(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Subject}}</title>
<style>
/* Base styles */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
background-color: #f9fafb;
color: #374151;
line-height: 1.5;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.header {
text-align: center;
padding: 20px 0;
border-bottom: 1px solid #e5e7eb;
}
.logo {
width: 60px;
height: 60px;
margin: 0 auto 15px;
background-color: #2563eb;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.logo-icon {
font-size: 24px;
color: white;
font-weight: bold;
}
h1 {
color: #111827;
font-size: 24px;
margin: 0;
}
.content {
padding: 30px 20px;
}
p {
margin: 0 0 15px;
color: #4b5563;
}
.info-box {
margin: 20px 0;
padding: 15px;
background-color: #f3f4f6;
border-radius: 6px;
color: #4b5563;
}
.info-item {
display: flex;
margin-bottom: 8px;
}
.info-label {
font-weight: bold;
width: 140px;
}
.note {
font-size: 14px;
color: #6b7280;
margin-top: 30px;
padding-top: 15px;
border-top: 1px solid #e5e7eb;
}
.footer {
text-align: center;
font-size: 12px;
color: #9ca3af;
padding: 20px 0;
background-color: #f9fafb;
border-radius: 0 0 8px 8px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">
<div class="logo-icon">G</div>
</div>
<h1>{{.Subject}}</h1>
</div>
<div class="content">
<p>{{.Message}}</p>
<div class="info-box">
<div class="info-item">
<div class="info-label">SMTP Server:</div>
<div>{{.SMTPServer}}:{{.SMTPPort}}</div>
</div>
<div class="info-item">
<div class="info-label">From:</div>
<div>{{.FromEmail}}</div>
</div>
<div class="info-item">
<div class="info-label">Sent:</div>
<div>{{.CurrentTime}}</div>
</div>
</div>
<div class="note">
<p>This is a test email sent from the GoMFT admin interface. If you've received this email, your email configuration is working correctly.</p>
</div>
</div>
<div class="footer">
<p>&copy; {{.Year}} {{.AppName}}. All rights reserved.</p>
</div>
</div>
</body>
</html>
`)
if err != nil {
return "", err
}
var result bytes.Buffer
if err := tmpl.Execute(&result, data); err != nil {
return "", err
}
return result.String(), nil
}
+56 -5
View File
@@ -63,17 +63,28 @@ func (h *Handlers) HandleAdminTools(c *gin.Context) {
data.TotalUsers = int(totalUsers)
}
// Get last backup time and backup count
data.LastBackupTime, data.BackupCount = h.getBackupInfo()
// Get backup info (last backup time and count)
lastBackup, backupCount := h.getBackupInfo()
data.LastBackupTime = lastBackup
data.BackupCount = backupCount
// Get list of backup files
data.BackupFiles = h.getBackupFiles()
// Check for maintenance issues
// Get maintenance message if any
data.MaintenanceMessage = h.checkMaintenanceIssues()
// Render the admin tools page
components.AdminTools(components.CreateTemplateContext(c), data).Render(c, c.Writer)
// Add SMTP server info if available
if h.Email != nil && h.Email.Config != nil && h.Email.Config.Email.Host != "" {
smtpServer := h.Email.Config.Email.Host
if h.Email.Config.Email.Port != 0 {
data.SmtpServer = fmt.Sprintf("%s:%d", smtpServer, h.Email.Config.Email.Port)
} else {
data.SmtpServer = smtpServer
}
}
components.AdminTools(c.Request.Context(), data).Render(c.Request.Context(), c.Writer)
}
// HandleBackupDatabase handles the backup database request
@@ -1368,3 +1379,43 @@ func (h *Handlers) HandleImportConfigsFromFile(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("%d configs imported successfully", imported)})
}
// HandleTestEmail handles the POST /admin/test-email route
func (h *Handlers) HandleTestEmail(c *gin.Context) {
// Parse the form
recipient := c.PostForm("recipient")
subject := c.PostForm("subject")
message := c.PostForm("message")
// Validate required fields
if recipient == "" {
components.EmailTestToast(false, "Recipient email is required").Render(c.Request.Context(), c.Writer)
return
}
// Get SMTP server info for display
smtpServer := ""
if h.Email != nil && h.Email.Config != nil && h.Email.Config.Email.Host != "" {
smtpServer = h.Email.Config.Email.Host
if h.Email.Config.Email.Port != 0 {
smtpServer = fmt.Sprintf("%s:%d", smtpServer, h.Email.Config.Email.Port)
}
}
// Send the test email
if h.Email == nil {
components.EmailTestToast(false, "Email service is not configured").Render(c.Request.Context(), c.Writer)
return
}
err := h.Email.SendTestEmail(recipient, subject, message)
if err != nil {
// Failed to send email
components.EmailTestToast(false, fmt.Sprintf("Failed to send email: %v", err)).Render(c.Request.Context(), c.Writer)
return
}
// Email sent successfully
successMsg := fmt.Sprintf("Test email sent successfully to %s", recipient)
components.EmailTestToast(true, successMsg).Render(c.Request.Context(), c.Writer)
}
+3
View File
@@ -110,6 +110,9 @@ func (h *Handlers) RegisterRoutes(router *gin.Engine) {
admin.GET("/logs/refresh", h.HandleRefreshLogs)
admin.GET("/logs/view/:fileName", h.HandleViewLog)
admin.GET("/logs/download/:fileName", h.HandleDownloadLog)
// Email test route
admin.POST("/test-email", h.HandleTestEmail)
}
// API routes