- Add Go modules with required dependencies (Gin, UUID, JWT, etc.) - Implement main web server with landing page endpoint - Add comprehensive API endpoints for health and status - Include proper error handling and request validation - Set up CORS middleware and security headers
278 lines
7.1 KiB
Go
278 lines
7.1 KiB
Go
package services
|
||
|
||
import (
|
||
"crypto/tls"
|
||
"fmt"
|
||
"net/smtp"
|
||
"time"
|
||
|
||
"github.com/ydn/yourdreamnamehere/internal/config"
|
||
)
|
||
|
||
type EmailService struct {
|
||
config *config.Config
|
||
auth smtp.Auth
|
||
}
|
||
|
||
func NewEmailService(config *config.Config) *EmailService {
|
||
auth := smtp.PlainAuth("", config.Email.SMTPUser, config.Email.SMTPPassword, config.Email.SMTPHost)
|
||
|
||
return &EmailService{
|
||
config: config,
|
||
auth: auth,
|
||
}
|
||
}
|
||
|
||
func (s *EmailService) SendWelcomeEmail(to, firstName string) error {
|
||
subject := "Welcome to YourDreamNameHere!"
|
||
body := fmt.Sprintf(`
|
||
Dear %s,
|
||
|
||
Welcome to YourDreamNameHere! Your sovereign data hosting journey begins now.
|
||
|
||
What happens next:
|
||
1. Your domain will be registered through our OVH partner
|
||
2. A VPS will be provisioned and configured for you
|
||
3. Cloudron will be installed on your VPS
|
||
4. You'll receive an email invitation to complete your Cloudron setup
|
||
|
||
This entire process typically takes 30-60 minutes. You'll receive updates at each step.
|
||
|
||
If you have any questions, please don't hesitate to contact our support team.
|
||
|
||
Best regards,
|
||
The YourDreamNameHere Team
|
||
`, firstName)
|
||
|
||
return s.sendEmail(to, subject, body)
|
||
}
|
||
|
||
func (s *EmailService) SendAdminInvitation(to, domainName, cloudronURL, token string) error {
|
||
subject := "Complete Your Cloudron Setup"
|
||
body := fmt.Sprintf(`
|
||
Your Cloudron instance is ready!
|
||
|
||
Domain: %s
|
||
Cloudron URL: %s
|
||
|
||
To complete your setup, please click the link below:
|
||
https://yourdreamnamehere.com/invitation/%s
|
||
|
||
This link will expire in 7 days.
|
||
|
||
What you'll need to do:
|
||
1. Set your administrator password
|
||
2. Configure your organization details
|
||
3. Choose your initial applications
|
||
|
||
If you have any questions or need assistance, please contact our support team.
|
||
|
||
Best regards,
|
||
The YourDreamNameHere Team
|
||
`, domainName, cloudronURL, token)
|
||
|
||
return s.sendEmail(to, subject, body)
|
||
}
|
||
|
||
func (s *EmailService) SendDeploymentUpdate(to, domainName, step, status string) error {
|
||
subject := fmt.Sprintf("Deployment Update for %s", domainName)
|
||
|
||
var statusMessage string
|
||
switch status {
|
||
case "completed":
|
||
statusMessage = "✅ Completed successfully"
|
||
case "failed":
|
||
statusMessage = "❌ Failed"
|
||
case "in_progress":
|
||
statusMessage = "🔄 In progress"
|
||
default:
|
||
statusMessage = "ℹ️ " + status
|
||
}
|
||
|
||
body := fmt.Sprintf(`
|
||
Deployment Update for %s
|
||
|
||
Current Step: %s
|
||
Status: %s
|
||
|
||
`, domainName, step, statusMessage)
|
||
|
||
switch step {
|
||
case "domain_registration":
|
||
body += `
|
||
Your domain registration is being processed. This typically takes a few minutes to complete.
|
||
`
|
||
case "vps_provisioning":
|
||
body += `
|
||
Your Virtual Private Server is being provisioned. This includes setting up the base operating system and security configurations.
|
||
`
|
||
case "cloudron_install":
|
||
body += `
|
||
Cloudron is being installed on your VPS. This is the most time-consuming step and can take 20-30 minutes.
|
||
`
|
||
case "deployment_complete":
|
||
body += `
|
||
🎉 Congratulations! Your sovereign data hosting environment is now ready!
|
||
|
||
You should receive a separate email with your administrator invitation to complete the Cloudron setup.
|
||
`
|
||
}
|
||
|
||
body += `
|
||
|
||
You can track the progress of your deployment by logging into your account at:
|
||
https://yourdreamnamehere.com/dashboard
|
||
|
||
Best regards,
|
||
The YourDreamNameHere Team
|
||
`
|
||
|
||
return s.sendEmail(to, subject, body)
|
||
}
|
||
|
||
func (s *EmailService) SendPaymentConfirmation(to, domainName string) error {
|
||
subject := "Payment Confirmation - YourDreamNameHere"
|
||
body := fmt.Sprintf(`
|
||
Payment Confirmation
|
||
|
||
Thank you for your payment! Your subscription for %s is now active.
|
||
|
||
Subscription Details:
|
||
- Domain: %s
|
||
- Plan: Sovereign Data Hosting
|
||
- Amount: $250.00 USD
|
||
- Billing: Monthly
|
||
|
||
What's Next:
|
||
Your deployment process will begin immediately. You'll receive email updates as each step completes.
|
||
|
||
If you have any questions, please contact our support team.
|
||
|
||
Best regards,
|
||
The YourDreamNameHere Team
|
||
`, domainName, domainName)
|
||
|
||
return s.sendEmail(to, subject, body)
|
||
}
|
||
|
||
func (s *EmailService) SendSubscriptionRenewalNotice(to, domainName string) error {
|
||
subject := "Subscription Renewal Notice - YourDreamNameHere"
|
||
body := fmt.Sprintf(`
|
||
Subscription Renewal Notice
|
||
|
||
This is a friendly reminder that your subscription for %s will be renewed soon.
|
||
|
||
Subscription Details:
|
||
- Domain: %s
|
||
- Plan: Sovereign Data Hosting
|
||
- Amount: $250.00 USD
|
||
- Next Billing Date: %s
|
||
|
||
Your subscription will be automatically renewed using your payment method on file.
|
||
|
||
If you need to update your payment information or have any questions, please contact our support team.
|
||
|
||
Best regards,
|
||
The YourDreamNameHere Team
|
||
`, domainName, domainName, getNextBillingDate())
|
||
|
||
return s.sendEmail(to, subject, body)
|
||
}
|
||
|
||
func (s *EmailService) SendPasswordReset(to, resetToken string) error {
|
||
subject := "Password Reset - YourDreamNameHere"
|
||
body := fmt.Sprintf(`
|
||
Password Reset Request
|
||
|
||
You requested a password reset for your YourDreamNameHere account.
|
||
|
||
Click the link below to reset your password:
|
||
https://yourdreamnamehere.com/reset-password?token=%s
|
||
|
||
This link will expire in 1 hour.
|
||
|
||
If you didn't request this password reset, please ignore this email or contact our support team.
|
||
|
||
Best regards,
|
||
The YourDreamNameHere Team
|
||
`, resetToken)
|
||
|
||
return s.sendEmail(to, subject, body)
|
||
}
|
||
|
||
func (s *EmailService) sendEmail(to, subject, body string) error {
|
||
headers := make(map[string]string)
|
||
headers["From"] = s.config.Email.From
|
||
headers["To"] = to
|
||
headers["Subject"] = subject
|
||
headers["MIME-Version"] = "1.0"
|
||
headers["Content-Type"] = "text/plain; charset=\"utf-8\""
|
||
|
||
message := ""
|
||
for k, v := range headers {
|
||
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
||
}
|
||
message += "\r\n" + body
|
||
|
||
// Create SMTP connection with TLS
|
||
client, err := s.createSMTPClient()
|
||
if err != nil {
|
||
return fmt.Errorf("failed to create SMTP client: %w", err)
|
||
}
|
||
defer client.Close()
|
||
|
||
// Set the sender and recipient
|
||
if err := client.Mail(s.config.Email.From); err != nil {
|
||
return fmt.Errorf("failed to set sender: %w", err)
|
||
}
|
||
|
||
if err := client.Rcpt(to); err != nil {
|
||
return fmt.Errorf("failed to set recipient: %w", err)
|
||
}
|
||
|
||
// Send the email body
|
||
w, err := client.Data()
|
||
if err != nil {
|
||
return fmt.Errorf("failed to create data writer: %w", err)
|
||
}
|
||
|
||
_, err = w.Write([]byte(message))
|
||
if err != nil {
|
||
return fmt.Errorf("failed to write email body: %w", err)
|
||
}
|
||
|
||
if err := w.Close(); err != nil {
|
||
return fmt.Errorf("failed to close data writer: %w", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (s *EmailService) createSMTPClient() (*smtp.Client, error) {
|
||
// Connect to SMTP server with TLS
|
||
conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%s", s.config.Email.SMTPHost, s.config.Email.SMTPPort), &tls.Config{
|
||
ServerName: s.config.Email.SMTPHost,
|
||
})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to connect to SMTP server: %w", err)
|
||
}
|
||
|
||
client, err := smtp.NewClient(conn, s.config.Email.SMTPHost)
|
||
if err != nil {
|
||
conn.Close()
|
||
return nil, fmt.Errorf("failed to create SMTP client: %w", err)
|
||
}
|
||
|
||
// Authenticate
|
||
if err := client.Auth(s.auth); err != nil {
|
||
client.Close()
|
||
return nil, fmt.Errorf("failed to authenticate: %w", err)
|
||
}
|
||
|
||
return client, nil
|
||
}
|
||
|
||
func getNextBillingDate() string {
|
||
// Return next month's date in a readable format
|
||
return time.Now().AddDate(0, 1, 0).Format("January 2, 2006")
|
||
} |