This commit is contained in:
parent
29aa5c2f36
commit
d0b672ac15
312
EMAIL_SETUP.md
Normal file
312
EMAIL_SETUP.md
Normal file
@ -0,0 +1,312 @@
|
||||
# Email Configuration Guide
|
||||
|
||||
## Overview
|
||||
The Brand Master application supports sending transactional emails for:
|
||||
- Password reset PINs
|
||||
- Welcome emails for new users
|
||||
- Order confirmations (future)
|
||||
- Contact form notifications (future)
|
||||
|
||||
## Email Service Options
|
||||
|
||||
### Option 1: Gmail SMTP (Recommended for Testing)
|
||||
|
||||
1. **Create App Password** (if using Gmail with 2FA):
|
||||
- Go to Google Account Settings → Security
|
||||
- Enable 2-Factor Authentication
|
||||
- Go to "App passwords"
|
||||
- Generate app password for "Mail"
|
||||
- Copy the 16-character password
|
||||
|
||||
2. **Configure Environment Variables**:
|
||||
```bash
|
||||
SMTP_HOST=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USERNAME=your-email@gmail.com
|
||||
SMTP_PASSWORD=your-app-password
|
||||
SMTP_FROM=noreply@brand-master.com
|
||||
```
|
||||
|
||||
### Option 2: SendGrid (Recommended for Production)
|
||||
|
||||
1. **Create SendGrid Account**:
|
||||
- Sign up at https://sendgrid.com
|
||||
- Verify your sender email
|
||||
- Create API key
|
||||
|
||||
2. **Configure Environment Variables**:
|
||||
```bash
|
||||
SMTP_HOST=smtp.sendgrid.net
|
||||
SMTP_PORT=587
|
||||
SMTP_USERNAME=apikey
|
||||
SMTP_PASSWORD=your-sendgrid-api-key
|
||||
SMTP_FROM=noreply@brand-master.com
|
||||
```
|
||||
|
||||
### Option 3: Amazon SES (Production - Most Reliable)
|
||||
|
||||
1. **Setup SES**:
|
||||
- Sign up for AWS SES
|
||||
- Verify your domain or email
|
||||
- Get SMTP credentials
|
||||
|
||||
2. **Configure Environment Variables**:
|
||||
```bash
|
||||
SMTP_HOST=email-smtp.us-east-1.amazonaws.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USERNAME=your-ses-smtp-username
|
||||
SMTP_PASSWORD=your-ses-smtp-password
|
||||
SMTP_FROM=noreply@brand-master.com
|
||||
```
|
||||
|
||||
## Kubernetes Deployment Configuration
|
||||
|
||||
### Method 1: Update values.yaml (Recommended)
|
||||
|
||||
Edit `brand-master-chart/values.yaml`:
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
env:
|
||||
# Existing vars...
|
||||
- name: SMTP_HOST
|
||||
value: "smtp.gmail.com"
|
||||
- name: SMTP_PORT
|
||||
value: "587"
|
||||
- name: SMTP_USERNAME
|
||||
value: "your-email@gmail.com"
|
||||
- name: SMTP_PASSWORD
|
||||
value: "your-app-password" # Use secrets in production!
|
||||
- name: SMTP_FROM
|
||||
value: "noreply@brand-master.com"
|
||||
```
|
||||
|
||||
### Method 2: Use Kubernetes Secret (Production)
|
||||
|
||||
1. **Create Secret**:
|
||||
```bash
|
||||
kubectl create secret generic brand-master-email \
|
||||
--from-literal=smtp-username=your-email@gmail.com \
|
||||
--from-literal=smtp-password=your-app-password \
|
||||
-n my-apps
|
||||
```
|
||||
|
||||
2. **Update Deployment** (`brand-master-chart/templates/backend-deployment.yaml`):
|
||||
```yaml
|
||||
env:
|
||||
# ... existing env vars ...
|
||||
- name: SMTP_HOST
|
||||
value: "smtp.gmail.com"
|
||||
- name: SMTP_PORT
|
||||
value: "587"
|
||||
- name: SMTP_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: brand-master-email
|
||||
key: smtp-username
|
||||
- name: SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: brand-master-email
|
||||
key: smtp-password
|
||||
- name: SMTP_FROM
|
||||
value: "noreply@brand-master.com"
|
||||
```
|
||||
|
||||
## Local Development (.env file)
|
||||
|
||||
Create `backend/.env`:
|
||||
|
||||
```env
|
||||
DATABASE_URL=postgresql://brand_master_user:your_password@localhost/brand_master_db
|
||||
JWT_SECRET_KEY=your-secret-key
|
||||
FRONTEND_URL=http://localhost:5173
|
||||
BACKEND_URL=http://localhost:8000
|
||||
|
||||
# Email Configuration
|
||||
SMTP_HOST=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USERNAME=your-email@gmail.com
|
||||
SMTP_PASSWORD=your-app-password
|
||||
SMTP_FROM=noreply@brand-master.com
|
||||
|
||||
# Admin Credentials
|
||||
ADMIN_EMAIL=admin@brandmaster.com
|
||||
ADMIN_PASSWORD=Admin123!
|
||||
```
|
||||
|
||||
## Testing Email Functionality
|
||||
|
||||
### Test Password Reset
|
||||
|
||||
1. **Trigger Password Reset**:
|
||||
```bash
|
||||
curl -X POST https://api-brand-master.dvirlabs.com/api/auth/request-reset-pin \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email": "user@example.com"}'
|
||||
```
|
||||
|
||||
2. **Check Email**:
|
||||
- User should receive email with 6-digit PIN
|
||||
- PIN expires in 15 minutes
|
||||
|
||||
3. **Reset Password**:
|
||||
```bash
|
||||
curl -X POST https://api-brand-master.dvirlabs.com/api/auth/reset-password-with-pin \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "user@example.com",
|
||||
"pin": "123456",
|
||||
"new_password": "NewPassword123!"
|
||||
}'
|
||||
```
|
||||
|
||||
### Test Welcome Email
|
||||
|
||||
1. **Register New User**:
|
||||
```bash
|
||||
curl -X POST https://api-brand-master.dvirlabs.com/api/auth/register \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "newuser@example.com",
|
||||
"full_name": "Test User",
|
||||
"password": "password123"
|
||||
}'
|
||||
```
|
||||
|
||||
2. **Check Email**:
|
||||
- User should receive welcome email
|
||||
|
||||
### Check Backend Logs
|
||||
|
||||
If emails aren't being sent:
|
||||
|
||||
```bash
|
||||
# View backend logs
|
||||
kubectl logs -n my-apps deployment/brand-master-backend -f
|
||||
|
||||
# Look for:
|
||||
# ✅ Email sent successfully to user@example.com
|
||||
# OR
|
||||
# ⚠️ SMTP not configured. Email would have been sent to: user@example.com
|
||||
# OR
|
||||
# ❌ Failed to send email to user@example.com: <error details>
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: "SMTP not configured" message
|
||||
|
||||
**Problem**: SMTP environment variables not set
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check if variables are set in pod
|
||||
kubectl exec -n my-apps deployment/brand-master-backend -- env | grep SMTP
|
||||
|
||||
# Should show:
|
||||
# SMTP_HOST=smtp.gmail.com
|
||||
# SMTP_PORT=587
|
||||
# SMTP_USERNAME=your-email@gmail.com
|
||||
# SMTP_PASSWORD=***
|
||||
# SMTP_FROM=noreply@brand-master.com
|
||||
```
|
||||
|
||||
### Issue: "Authentication failed" error
|
||||
|
||||
**Problem**: Wrong credentials or app password required
|
||||
|
||||
**Solution**:
|
||||
- For Gmail: Use App Password, not account password
|
||||
- Verify credentials are correct
|
||||
- Check if 2FA is enabled (required for App Passwords)
|
||||
|
||||
### Issue: "Connection refused" error
|
||||
|
||||
**Problem**: Wrong SMTP host or port, or firewall blocking
|
||||
|
||||
**Solution**:
|
||||
- Verify SMTP_HOST and SMTP_PORT are correct
|
||||
- Check Kubernetes network policies
|
||||
- Test SMTP connection from pod:
|
||||
```bash
|
||||
kubectl exec -n my-apps deployment/brand-master-backend -- \
|
||||
nc -zv smtp.gmail.com 587
|
||||
```
|
||||
|
||||
### Issue: Emails go to spam
|
||||
|
||||
**Problem**: Missing SPF/DKIM records or sender reputation
|
||||
|
||||
**Solution**:
|
||||
- Use verified domain with proper DNS records
|
||||
- Use SendGrid or SES for production
|
||||
- Add SPF record: `v=spf1 include:_spf.google.com ~all`
|
||||
- Setup DKIM signing
|
||||
|
||||
## Email Templates
|
||||
|
||||
Email templates are in `backend/app/services/email.py`:
|
||||
|
||||
- `send_password_reset_pin()` - Password reset with PIN
|
||||
- `send_welcome_email()` - Welcome new users
|
||||
|
||||
To customize:
|
||||
1. Edit template in `email.py`
|
||||
2. Rebuild backend image
|
||||
3. Redeploy
|
||||
|
||||
## Production Best Practices
|
||||
|
||||
1. ✅ **Use Kubernetes Secrets** for credentials
|
||||
2. ✅ **Use dedicated email service** (SendGrid, SES)
|
||||
3. ✅ **Setup SPF/DKIM** for deliverability
|
||||
4. ✅ **Monitor email sending** (logs, metrics)
|
||||
5. ✅ **Implement rate limiting** to prevent abuse
|
||||
6. ✅ **Use verified sender domain**
|
||||
7. ✅ **Add unsubscribe links** for marketing emails
|
||||
8. ✅ **Keep templates professional** and branded
|
||||
|
||||
## Quick Setup for Testing (Gmail)
|
||||
|
||||
```bash
|
||||
# 1. Update values.yaml
|
||||
nano brand-master-chart/values.yaml
|
||||
|
||||
# Add under backend.env:
|
||||
- name: SMTP_HOST
|
||||
value: "smtp.gmail.com"
|
||||
- name: SMTP_PORT
|
||||
value: "587"
|
||||
- name: SMTP_USERNAME
|
||||
value: "your-email@gmail.com"
|
||||
- name: SMTP_PASSWORD
|
||||
value: "your-16-char-app-password"
|
||||
- name: SMTP_FROM
|
||||
value: "Brand Master <noreply@brand-master.com>"
|
||||
|
||||
# 2. Redeploy
|
||||
cd brand-master-chart
|
||||
helm upgrade brand-master . --namespace my-apps --wait
|
||||
|
||||
# 3. Test
|
||||
curl -X POST https://api-brand-master.dvirlabs.com/api/auth/request-reset-pin \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email": "your-test-email@gmail.com"}'
|
||||
|
||||
# 4. Check email inbox
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
If emails still don't work:
|
||||
1. Check backend logs for error messages
|
||||
2. Verify SMTP credentials
|
||||
3. Test SMTP connection manually
|
||||
4. Check spam folder
|
||||
5. Try different email provider
|
||||
|
||||
---
|
||||
|
||||
**Status**: Email service implemented and ready to configure
|
||||
**Last Updated**: May 8, 2026
|
||||
304
PASSWORD_RESET_GUIDE.md
Normal file
304
PASSWORD_RESET_GUIDE.md
Normal file
@ -0,0 +1,304 @@
|
||||
# Password Reset with Email PIN - Implementation Summary
|
||||
|
||||
## What Was Implemented
|
||||
|
||||
### 1. Email Service Module ✅
|
||||
**File**: `backend/app/services/email.py`
|
||||
|
||||
**Features**:
|
||||
- `send_email()` - Generic SMTP email sender
|
||||
- `send_password_reset_pin()` - Sends 6-digit PIN with HTML/plain text template
|
||||
- `send_welcome_email()` - Welcome new users
|
||||
- Graceful fallback: Prints to console if SMTP not configured
|
||||
- Professional HTML email templates with branding
|
||||
|
||||
**Template Highlights**:
|
||||
- Beautiful HTML design with Brand Master branding
|
||||
- 6-digit PIN displayed prominently
|
||||
- 15-minute expiration timer
|
||||
- Instructions for password reset
|
||||
- Responsive design
|
||||
- Plain text fallback
|
||||
|
||||
### 2. Auth Router Integration ✅
|
||||
**File**: `backend/app/routers/auth.py`
|
||||
|
||||
**Changes**:
|
||||
- Imported email service functions
|
||||
- Updated `request_reset_pin()` to send email instead of just printing
|
||||
- Updated `register()` to send welcome email to new users
|
||||
- Added error handling (non-blocking - won't fail if email fails)
|
||||
- Removed PIN from API response (security fix)
|
||||
|
||||
**Flow**:
|
||||
1. User requests password reset with email
|
||||
2. System generates 6-digit PIN
|
||||
3. Stores PIN in database with 15-minute expiration
|
||||
4. **Sends PIN to user's email** (new!)
|
||||
5. Falls back to console print if SMTP not configured
|
||||
6. User enters PIN and new password
|
||||
7. System validates PIN and updates password
|
||||
|
||||
### 3. Configuration Guide ✅
|
||||
**File**: `EMAIL_SETUP.md`
|
||||
|
||||
**Includes**:
|
||||
- 3 email provider options (Gmail, SendGrid, AWS SES)
|
||||
- Step-by-step setup for each provider
|
||||
- Kubernetes deployment configuration
|
||||
- Secret management (production best practices)
|
||||
- Testing instructions
|
||||
- Troubleshooting guide
|
||||
- Production checklist
|
||||
|
||||
### 4. Quick Fix Deployment Script ✅
|
||||
**File**: `quick-fix.bat`
|
||||
|
||||
**Automates**:
|
||||
- Applies both database migrations (007, 008)
|
||||
- Builds backend and frontend Docker images
|
||||
- Pushes to Harbor registry
|
||||
- Deploys via Helm
|
||||
- Shows next steps and instructions
|
||||
|
||||
## What You Need to Do
|
||||
|
||||
### REQUIRED Steps
|
||||
|
||||
#### 1. Apply Database Migrations (CRITICAL)
|
||||
The system currently has errors because migrations aren't applied:
|
||||
|
||||
```bash
|
||||
# Option A: Use quick-fix script (does everything)
|
||||
quick-fix.bat
|
||||
|
||||
# Option B: Apply migrations manually
|
||||
apply-migration.bat 007_enhance_contact_messages.sql
|
||||
apply-migration.bat 008_add_username_to_users.sql
|
||||
```
|
||||
|
||||
**These migrations fix**:
|
||||
- ❌ "column full_name does not exist" → ✅ Renames name → full_name
|
||||
- ❌ "column username does not exist" → ✅ Adds username column
|
||||
|
||||
#### 2. Configure Email (for password reset to work)
|
||||
|
||||
**Quick Setup (Gmail)**:
|
||||
|
||||
1. Get Gmail App Password:
|
||||
- Go to https://myaccount.google.com/apppasswords
|
||||
- Generate password for "Mail"
|
||||
- Copy 16-character password
|
||||
|
||||
2. Update `brand-master-chart/values.yaml`:
|
||||
```yaml
|
||||
backend:
|
||||
env:
|
||||
# ... existing vars ...
|
||||
- name: SMTP_HOST
|
||||
value: "smtp.gmail.com"
|
||||
- name: SMTP_PORT
|
||||
value: "587"
|
||||
- name: SMTP_USERNAME
|
||||
value: "your-email@gmail.com"
|
||||
- name: SMTP_PASSWORD
|
||||
value: "abcd efgh ijkl mnop" # Your 16-char app password
|
||||
- name: SMTP_FROM
|
||||
value: "Brand Master <noreply@brand-master.com>"
|
||||
```
|
||||
|
||||
3. Redeploy:
|
||||
```bash
|
||||
cd brand-master-chart
|
||||
helm upgrade brand-master . --namespace my-apps --wait
|
||||
```
|
||||
|
||||
**Read [EMAIL_SETUP.md](EMAIL_SETUP.md) for**:
|
||||
- Other email providers (SendGrid, AWS SES)
|
||||
- Production setup with Kubernetes Secrets
|
||||
- Troubleshooting guide
|
||||
|
||||
### OPTIONAL Steps
|
||||
|
||||
#### 3. Test Email Functionality
|
||||
|
||||
**Test Password Reset**:
|
||||
```bash
|
||||
# Request PIN
|
||||
curl -X POST https://api-brand-master.dvirlabs.com/api/auth/request-reset-pin \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email": "your-test-email@gmail.com"}'
|
||||
|
||||
# Check your email for 6-digit PIN
|
||||
|
||||
# Reset password
|
||||
curl -X POST https://api-brand-master.dvirlabs.com/api/auth/reset-password-with-pin \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "your-test-email@gmail.com",
|
||||
"pin": "123456",
|
||||
"new_password": "NewPassword123!"
|
||||
}'
|
||||
```
|
||||
|
||||
**Or test via UI**:
|
||||
1. Go to https://brand-master.dvirlabs.com/login
|
||||
2. Click "Forgot Password?"
|
||||
3. Enter email
|
||||
4. Check inbox for PIN
|
||||
5. Enter PIN and new password
|
||||
|
||||
#### 4. Monitor Email Sending
|
||||
|
||||
```bash
|
||||
# View backend logs
|
||||
kubectl logs -n my-apps deployment/brand-master-backend -f
|
||||
|
||||
# Look for:
|
||||
# ✅ Email sent successfully to user@example.com
|
||||
# ⚠️ SMTP not configured. Email would have been sent to: ...
|
||||
# ❌ Failed to send email: <error>
|
||||
```
|
||||
|
||||
## Current Status
|
||||
|
||||
| Feature | Status | Notes |
|
||||
|---------|--------|-------|
|
||||
| Email service code | ✅ Complete | `backend/app/services/email.py` created |
|
||||
| Password reset PIN email | ✅ Complete | Sends HTML email with 6-digit PIN |
|
||||
| Welcome email | ✅ Complete | Sent on new user registration |
|
||||
| Auth router integration | ✅ Complete | Email functions called in endpoints |
|
||||
| Configuration guide | ✅ Complete | See `EMAIL_SETUP.md` |
|
||||
| Deployment script | ✅ Complete | `quick-fix.bat` |
|
||||
| Database migrations | ⚠️ **NOT APPLIED** | Must run migrations! |
|
||||
| SMTP configuration | ⚠️ **NOT CONFIGURED** | Emails print to console until configured |
|
||||
| Production deployment | ⚠️ Pending | Need to rebuild/redeploy |
|
||||
|
||||
## How It Works Now
|
||||
|
||||
### Without SMTP Configured (Current State)
|
||||
|
||||
**What happens**:
|
||||
1. User requests password reset
|
||||
2. System generates PIN
|
||||
3. **Email service prints to console**:
|
||||
```
|
||||
⚠️ SMTP not configured. Email would have been sent to: user@example.com
|
||||
Subject: Brand Master - Password Reset PIN
|
||||
Body: Your PIN is: 123456
|
||||
```
|
||||
4. You check backend logs for the PIN
|
||||
5. User can still reset password with the PIN
|
||||
|
||||
**This is fine for testing but not production!**
|
||||
|
||||
### With SMTP Configured (After Setup)
|
||||
|
||||
**What happens**:
|
||||
1. User requests password reset
|
||||
2. System generates PIN
|
||||
3. **Email sent to user's inbox** ✅
|
||||
4. User receives beautiful HTML email with PIN
|
||||
5. User resets password (no need to check logs)
|
||||
|
||||
## Files Changed
|
||||
|
||||
### Created
|
||||
- ✅ `backend/app/services/email.py` - Email service module
|
||||
- ✅ `EMAIL_SETUP.md` - Email configuration guide
|
||||
- ✅ `quick-fix.bat` - Automated deployment script
|
||||
- ✅ `PASSWORD_RESET_GUIDE.md` - This file
|
||||
|
||||
### Modified
|
||||
- ✅ `backend/app/routers/auth.py` - Integrated email service
|
||||
|
||||
### Ready to Apply
|
||||
- ⚠️ `backend/migrations/007_enhance_contact_messages.sql`
|
||||
- ⚠️ `backend/migrations/008_add_username_to_users.sql`
|
||||
|
||||
## Quick Start Commands
|
||||
|
||||
### Full Automated Deployment
|
||||
```bash
|
||||
# This does everything: migrations + build + deploy
|
||||
quick-fix.bat
|
||||
```
|
||||
|
||||
### Manual Step-by-Step
|
||||
```bash
|
||||
# 1. Apply migrations
|
||||
apply-migration.bat 007_enhance_contact_messages.sql
|
||||
apply-migration.bat 008_add_username_to_users.sql
|
||||
|
||||
# 2. Build images
|
||||
cd backend && docker build -t harbor.dvirlabs.com/my-apps/brand-master-backend:latest . && cd ..
|
||||
cd frontend && docker build -t harbor.dvirlabs.com/my-apps/brand-master-frontend:latest . && cd ..
|
||||
|
||||
# 3. Push images
|
||||
docker push harbor.dvirlabs.com/my-apps/brand-master-backend:latest
|
||||
docker push harbor.dvirlabs.com/my-apps/brand-master-frontend:latest
|
||||
|
||||
# 4. Deploy
|
||||
cd brand-master-chart
|
||||
helm upgrade brand-master . --namespace my-apps --wait
|
||||
```
|
||||
|
||||
## Email Provider Recommendations
|
||||
|
||||
| Provider | Best For | Cost | Setup Difficulty |
|
||||
|----------|----------|------|------------------|
|
||||
| **Gmail** | Testing, Development | Free | Easy (App Password) |
|
||||
| **SendGrid** | Production (Small) | Free tier: 100 emails/day | Medium |
|
||||
| **AWS SES** | Production (Large) | $0.10 per 1000 emails | Medium-Hard |
|
||||
| **Mailgun** | Production | Free tier: 5000 emails/month | Medium |
|
||||
|
||||
**My Recommendation**:
|
||||
- **For testing now**: Gmail (5 minutes to setup)
|
||||
- **For production later**: SendGrid or AWS SES (better deliverability)
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
After deployment:
|
||||
|
||||
- [ ] Can submit contact form without errors
|
||||
- [ ] Can register with username and phone
|
||||
- [ ] Can login with email, username, OR phone
|
||||
- [ ] Can request password reset
|
||||
- [ ] Receive PIN email (or see in logs if SMTP not configured)
|
||||
- [ ] Can reset password with PIN
|
||||
- [ ] PIN expires after 15 minutes
|
||||
- [ ] Invalid PIN shows error
|
||||
- [ ] Welcome email sent on registration
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Column full_name does not exist"
|
||||
**Fix**: Run `apply-migration.bat 007_enhance_contact_messages.sql`
|
||||
|
||||
### "Column username does not exist"
|
||||
**Fix**: Run `apply-migration.bat 008_add_username_to_users.sql`
|
||||
|
||||
### "SMTP not configured" in logs
|
||||
**Fix**: Configure SMTP in `values.yaml` (see [EMAIL_SETUP.md](EMAIL_SETUP.md))
|
||||
|
||||
### PIN not received in email
|
||||
**Fix**: Check backend logs for error message, verify SMTP credentials
|
||||
|
||||
### Emails go to spam
|
||||
**Fix**: Use proper From address, setup SPF/DKIM, or use SendGrid/SES
|
||||
|
||||
## Next Features (Future)
|
||||
|
||||
Possible enhancements:
|
||||
- ✉️ Order confirmation emails
|
||||
- ✉️ Shipping notification emails
|
||||
- ✉️ Contact form notification to admin
|
||||
- ✉️ Email templates customization UI
|
||||
- 📊 Email delivery tracking
|
||||
- 🎨 Email template builder
|
||||
|
||||
---
|
||||
|
||||
**Implementation Date**: January 2025
|
||||
**Status**: Ready to deploy (migrations required)
|
||||
**Documentation**: EMAIL_SETUP.md, API_DOCUMENTATION.md
|
||||
@ -1,5 +1,20 @@
|
||||
@echo off
|
||||
REM Apply database migration 005 - Add password reset fields
|
||||
REM Apply database migration script
|
||||
REM Usage: apply-migration.bat <migration_filename>
|
||||
|
||||
if "%1"=="" (
|
||||
echo ❌ Error: No migration file specified
|
||||
echo Usage: apply-migration.bat ^<migration_filename^>
|
||||
echo Example: apply-migration.bat 007_enhance_contact_messages.sql
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set MIGRATION_FILE=%1
|
||||
|
||||
if not exist "backend\migrations\%MIGRATION_FILE%" (
|
||||
echo ❌ Migration file not found: backend\migrations\%MIGRATION_FILE%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Getting database pod name...
|
||||
for /f "delims=" %%i in ('kubectl get pod -n my-apps -l app.kubernetes.io/component=db -o jsonpath^="{.items[0].metadata.name}"') do set DB_POD=%%i
|
||||
@ -10,17 +25,17 @@ if "%DB_POD%"=="" (
|
||||
)
|
||||
|
||||
echo 📦 Database pod: %DB_POD%
|
||||
echo 📝 Applying migration 005_add_password_reset_fields.sql...
|
||||
echo 📝 Applying migration: %MIGRATION_FILE%...
|
||||
echo.
|
||||
|
||||
REM Copy migration file to pod
|
||||
kubectl cp backend/migrations/005_add_password_reset_fields.sql my-apps/%DB_POD%:/tmp/migration.sql
|
||||
kubectl cp backend/migrations/%MIGRATION_FILE% my-apps/%DB_POD%:/tmp/migration.sql
|
||||
|
||||
REM Execute migration
|
||||
kubectl exec -n my-apps %DB_POD% -- psql -U brand_master_user -d brand_master_db -f /tmp/migration.sql
|
||||
|
||||
echo.
|
||||
echo ✅ Migration applied successfully!
|
||||
echo ✅ Migration %MIGRATION_FILE% applied successfully!
|
||||
echo.
|
||||
echo 🔄 Restarting backend pod to pick up changes...
|
||||
kubectl delete pod -n my-apps -l app.kubernetes.io/component=backend
|
||||
|
||||
@ -15,6 +15,7 @@ from app.services.auth import (
|
||||
verify_password,
|
||||
get_current_user,
|
||||
)
|
||||
from app.services.email import send_password_reset_pin, send_welcome_email
|
||||
from app.config import settings
|
||||
|
||||
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
||||
@ -43,15 +44,42 @@ def register(user: UserCreate, db: Session = Depends(get_db)):
|
||||
detail="Email already registered",
|
||||
)
|
||||
|
||||
# Check if username is already taken
|
||||
if user.username:
|
||||
existing_username = db.query(User).filter(User.username == user.username).first()
|
||||
if existing_username:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Username already taken",
|
||||
)
|
||||
|
||||
# Check if phone is already taken
|
||||
if user.phone:
|
||||
existing_phone = db.query(User).filter(User.phone == user.phone).first()
|
||||
if existing_phone:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Phone number already registered",
|
||||
)
|
||||
|
||||
hashed_password = get_password_hash(user.password)
|
||||
db_user = User(
|
||||
email=user.email,
|
||||
username=user.username,
|
||||
phone=user.phone,
|
||||
full_name=user.full_name,
|
||||
hashed_password=hashed_password,
|
||||
)
|
||||
db.add(db_user)
|
||||
db.commit()
|
||||
db.refresh(db_user)
|
||||
|
||||
# Send welcome email (non-blocking - don't fail registration if email fails)
|
||||
try:
|
||||
send_welcome_email(user.email, user.full_name)
|
||||
except Exception as e:
|
||||
print(f"Failed to send welcome email: {e}")
|
||||
|
||||
return db_user
|
||||
|
||||
|
||||
@ -132,14 +160,16 @@ def reset_password(request: ResetPasswordRequest, db: Session = Depends(get_db))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="User not found",
|
||||
)
|
||||
Send PIN via email
|
||||
email_sent = send_password_reset_pin(request.email, pin, expires_minutes=15)
|
||||
|
||||
# Update password
|
||||
user.hashed_password = get_password_hash(request.new_password)
|
||||
db.commit()
|
||||
|
||||
return {"message": "Password reset successful"}
|
||||
if not email_sent:
|
||||
# If email sending fails, still print to console for development
|
||||
print(f"\n⚠️ Email not sent. Password Reset PIN for {request.email}: {pin}")
|
||||
print(f"Expires at: {user.pin_expires_at}\n")
|
||||
|
||||
return {
|
||||
"message": "If the email exists, a PIN has been sent to your email",
|
||||
|
||||
@router.post("/request-reset-pin")
|
||||
def request_reset_pin(request: RequestPinRequest, db: Session = Depends(get_db)):
|
||||
|
||||
233
backend/app/services/email.py
Normal file
233
backend/app/services/email.py
Normal file
@ -0,0 +1,233 @@
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from typing import Optional
|
||||
from app.config import settings
|
||||
|
||||
|
||||
def send_email(
|
||||
to_email: str,
|
||||
subject: str,
|
||||
body: str,
|
||||
html_body: Optional[str] = None
|
||||
) -> bool:
|
||||
"""
|
||||
Send an email using SMTP configuration from settings.
|
||||
|
||||
Args:
|
||||
to_email: Recipient email address
|
||||
subject: Email subject
|
||||
body: Plain text body
|
||||
html_body: Optional HTML body (if provided, will be sent as multipart)
|
||||
|
||||
Returns:
|
||||
bool: True if email sent successfully, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Create message
|
||||
message = MIMEMultipart('alternative') if html_body else MIMEText(body, 'plain')
|
||||
|
||||
if html_body:
|
||||
message['Subject'] = subject
|
||||
message['From'] = settings.smtp_from
|
||||
message['To'] = to_email
|
||||
|
||||
# Attach plain text and HTML versions
|
||||
part1 = MIMEText(body, 'plain')
|
||||
part2 = MIMEText(html_body, 'html')
|
||||
message.attach(part1)
|
||||
message.attach(part2)
|
||||
else:
|
||||
message['Subject'] = subject
|
||||
message['From'] = settings.smtp_from
|
||||
message['To'] = to_email
|
||||
|
||||
# Check if SMTP is configured
|
||||
if not settings.smtp_username or not settings.smtp_password:
|
||||
print(f"⚠️ SMTP not configured. Email would have been sent to: {to_email}")
|
||||
print(f"Subject: {subject}")
|
||||
print(f"Body:\n{body}")
|
||||
return False
|
||||
|
||||
# Connect to SMTP server
|
||||
with smtplib.SMTP(settings.smtp_host, settings.smtp_port) as server:
|
||||
server.starttls()
|
||||
server.login(settings.smtp_username, settings.smtp_password)
|
||||
server.send_message(message)
|
||||
|
||||
print(f"✅ Email sent successfully to {to_email}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to send email to {to_email}: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def send_password_reset_pin(email: str, pin: str, expires_minutes: int = 15) -> bool:
|
||||
"""
|
||||
Send password reset PIN email.
|
||||
|
||||
Args:
|
||||
email: User's email address
|
||||
pin: 6-digit PIN code
|
||||
expires_minutes: Minutes until PIN expires
|
||||
|
||||
Returns:
|
||||
bool: True if email sent successfully
|
||||
"""
|
||||
subject = "Brand Master - Password Reset PIN"
|
||||
|
||||
# Plain text version
|
||||
body = f"""
|
||||
Hello,
|
||||
|
||||
You requested a password reset for your Brand Master account.
|
||||
|
||||
Your 6-digit PIN code is: {pin}
|
||||
|
||||
This PIN will expire in {expires_minutes} minutes.
|
||||
|
||||
To reset your password:
|
||||
1. Go to the login page
|
||||
2. Click "Forgot Password"
|
||||
3. Enter this PIN when prompted
|
||||
4. Create your new password
|
||||
|
||||
If you didn't request this reset, please ignore this email.
|
||||
|
||||
Best regards,
|
||||
Brand Master Team
|
||||
"""
|
||||
|
||||
# HTML version
|
||||
html_body = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
|
||||
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
|
||||
.header {{ background: #007bff; color: white; padding: 20px; text-align: center; border-radius: 5px 5px 0 0; }}
|
||||
.content {{ background: #f9f9f9; padding: 30px; border-radius: 0 0 5px 5px; }}
|
||||
.pin-box {{ background: white; padding: 20px; text-align: center; border: 2px solid #007bff; border-radius: 5px; margin: 20px 0; }}
|
||||
.pin {{ font-size: 32px; font-weight: bold; color: #007bff; letter-spacing: 5px; }}
|
||||
.warning {{ color: #dc3545; font-weight: bold; }}
|
||||
.footer {{ text-align: center; color: #666; margin-top: 20px; font-size: 12px; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Password Reset Request</h1>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>Hello,</p>
|
||||
<p>You requested a password reset for your Brand Master account.</p>
|
||||
|
||||
<div class="pin-box">
|
||||
<p style="margin: 0; font-size: 14px;">Your 6-digit PIN code is:</p>
|
||||
<p class="pin">{pin}</p>
|
||||
<p style="margin: 0; color: #666;">Expires in {expires_minutes} minutes</p>
|
||||
</div>
|
||||
|
||||
<p><strong>To reset your password:</strong></p>
|
||||
<ol>
|
||||
<li>Go to the <a href="https://brand-master.dvirlabs.com/login">login page</a></li>
|
||||
<li>Click "Forgot Password"</li>
|
||||
<li>Enter this PIN when prompted</li>
|
||||
<li>Create your new password</li>
|
||||
</ol>
|
||||
|
||||
<p class="warning">⚠️ If you didn't request this reset, please ignore this email.</p>
|
||||
|
||||
<div class="footer">
|
||||
<p>This is an automated message from Brand Master. Please do not reply.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
return send_email(email, subject, body, html_body)
|
||||
|
||||
|
||||
def send_welcome_email(email: str, full_name: str) -> bool:
|
||||
"""
|
||||
Send welcome email to new users.
|
||||
|
||||
Args:
|
||||
email: User's email address
|
||||
full_name: User's full name
|
||||
|
||||
Returns:
|
||||
bool: True if email sent successfully
|
||||
"""
|
||||
subject = "Welcome to Brand Master!"
|
||||
|
||||
body = f"""
|
||||
Hello {full_name},
|
||||
|
||||
Welcome to Brand Master! Your account has been created successfully.
|
||||
|
||||
You can now:
|
||||
- Browse our collection of premium shoes and apparel
|
||||
- Add items to your wishlist
|
||||
- Place orders with secure checkout
|
||||
- Track your order history
|
||||
|
||||
Visit us at: https://brand-master.dvirlabs.com
|
||||
|
||||
Best regards,
|
||||
Brand Master Team
|
||||
"""
|
||||
|
||||
html_body = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
|
||||
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
|
||||
.header {{ background: linear-gradient(135deg, #007bff 0%, #0056b3 100%); color: white; padding: 30px; text-align: center; border-radius: 5px 5px 0 0; }}
|
||||
.content {{ background: #f9f9f9; padding: 30px; border-radius: 0 0 5px 5px; }}
|
||||
.button {{ display: inline-block; padding: 12px 30px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; margin: 20px 0; }}
|
||||
.features {{ background: white; padding: 20px; border-radius: 5px; margin: 20px 0; }}
|
||||
.footer {{ text-align: center; color: #666; margin-top: 20px; font-size: 12px; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Welcome to Brand Master!</h1>
|
||||
<p>Your premium fashion destination</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>Hello {full_name},</p>
|
||||
<p>Welcome aboard! Your account has been created successfully.</p>
|
||||
|
||||
<div class="features">
|
||||
<h3>What you can do:</h3>
|
||||
<ul>
|
||||
<li>✅ Browse our collection of premium shoes and apparel</li>
|
||||
<li>✅ Add items to your wishlist</li>
|
||||
<li>✅ Place orders with secure checkout</li>
|
||||
<li>✅ Track your order history</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="https://brand-master.dvirlabs.com" class="button">Start Shopping</a>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>Questions? Contact us at info@brandmaster.com</p>
|
||||
<p>This is an automated message from Brand Master.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
return send_email(email, subject, body, html_body)
|
||||
109
quick-fix.bat
Normal file
109
quick-fix.bat
Normal file
@ -0,0 +1,109 @@
|
||||
@echo off
|
||||
REM Quick Fix Script - Apply Migrations and Deploy
|
||||
REM This script fixes the database errors and deploys the updated system
|
||||
|
||||
echo ================================================================
|
||||
echo Brand Master - Quick Fix Deployment
|
||||
echo ================================================================
|
||||
echo.
|
||||
echo This will:
|
||||
echo 1. Apply contact messages migration (fix full_name error)
|
||||
echo 2. Apply flexible login migration (fix username error)
|
||||
echo 3. Rebuild and deploy backend/frontend
|
||||
echo.
|
||||
pause
|
||||
|
||||
REM Step 1: Apply Contact Messages Migration
|
||||
echo ================================================================
|
||||
echo Step 1: Applying contact messages migration...
|
||||
echo ================================================================
|
||||
call apply-migration.bat 007_enhance_contact_messages.sql
|
||||
if errorlevel 1 (
|
||||
echo [ERROR] Failed to apply contact messages migration
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo.
|
||||
|
||||
REM Step 2: Apply Flexible Login Migration
|
||||
echo ================================================================
|
||||
echo Step 2: Applying flexible login migration...
|
||||
echo ================================================================
|
||||
call apply-migration.bat 008_add_username_to_users.sql
|
||||
if errorlevel 1 (
|
||||
echo [ERROR] Failed to apply flexible login migration
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo.
|
||||
|
||||
REM Step 3: Build and Deploy
|
||||
echo ================================================================
|
||||
echo Step 3: Building and deploying...
|
||||
echo ================================================================
|
||||
|
||||
set BACKEND_IMAGE=harbor.dvirlabs.com/my-apps/brand-master-backend:latest
|
||||
set FRONTEND_IMAGE=harbor.dvirlabs.com/my-apps/brand-master-frontend:latest
|
||||
|
||||
echo Building backend...
|
||||
cd backend
|
||||
docker build -t %BACKEND_IMAGE% .
|
||||
if errorlevel 1 (
|
||||
echo [ERROR] Backend build failed
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
cd ..
|
||||
|
||||
echo Building frontend...
|
||||
cd frontend
|
||||
docker build -t %FRONTEND_IMAGE% .
|
||||
if errorlevel 1 (
|
||||
echo [ERROR] Frontend build failed
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
cd ..
|
||||
|
||||
echo Pushing images...
|
||||
docker push %BACKEND_IMAGE%
|
||||
docker push %FRONTEND_IMAGE%
|
||||
|
||||
echo Deploying to Kubernetes...
|
||||
cd brand-master-chart
|
||||
helm upgrade brand-master . --namespace my-apps --wait --timeout 5m
|
||||
cd ..
|
||||
|
||||
echo.
|
||||
echo ================================================================
|
||||
echo Deployment Complete!
|
||||
echo ================================================================
|
||||
echo.
|
||||
echo FIXED ISSUES:
|
||||
echo ✅ Contact form "full_name" error - FIXED
|
||||
echo ✅ Password reset "username" error - FIXED
|
||||
echo ✅ Email sending functionality - ADDED
|
||||
echo.
|
||||
echo NEXT STEPS:
|
||||
echo.
|
||||
echo 1. CONFIGURE EMAIL (Required for password reset to work):
|
||||
echo - Read EMAIL_SETUP.md for detailed instructions
|
||||
echo - Quick setup: Update brand-master-chart/values.yaml with SMTP settings
|
||||
echo - Or check backend logs for PIN (printed to console if email not configured)
|
||||
echo.
|
||||
echo 2. TEST PASSWORD RESET:
|
||||
echo - Go to login page
|
||||
echo - Click "Forgot Password"
|
||||
echo - Enter your email
|
||||
echo - Check email for PIN (or backend logs if email not configured)
|
||||
echo - Enter PIN and new password
|
||||
echo.
|
||||
echo 3. VIEW BACKEND LOGS:
|
||||
echo kubectl logs -n my-apps deployment/brand-master-backend -f
|
||||
echo.
|
||||
echo 4. CHECK EMAIL CONFIGURATION:
|
||||
echo kubectl exec -n my-apps deployment/brand-master-backend -- env ^| findstr SMTP
|
||||
echo.
|
||||
echo FOR EMAIL SETUP HELP: See EMAIL_SETUP.md
|
||||
echo.
|
||||
pause
|
||||
Loading…
x
Reference in New Issue
Block a user