615 lines
15 KiB
Markdown
615 lines
15 KiB
Markdown
# Gateway Testing via Admin Interface
|
|
|
|
## Overview
|
|
|
|
The admin interface now includes a comprehensive gateway testing module that allows you to:
|
|
- Check gateway connection status in real-time
|
|
- Send test SMS messages through specific gateways
|
|
- Verify gateway functionality without external tools
|
|
- Debug connection issues
|
|
|
|
## Features
|
|
|
|
### 1. Connection Status Check
|
|
|
|
**Real-time Gateway Status**:
|
|
- ✅ Online/Offline detection
|
|
- ⏰ Last heartbeat timestamp
|
|
- 🕐 Time since last connection
|
|
- 🔄 One-click refresh
|
|
|
|
**How It Works**:
|
|
- Checks if gateway sent heartbeat within last 2 minutes
|
|
- Displays exact last heartbeat time
|
|
- Shows human-readable "time ago" format
|
|
- Updates with AJAX (no page reload)
|
|
|
|
### 2. Send Test SMS
|
|
|
|
**Test Message Features**:
|
|
- 📱 Phone number validation
|
|
- ✉️ Custom message composition
|
|
- 📊 Character counter (160 char SMS limit)
|
|
- 📝 Multi-part SMS detection
|
|
- ✅ Success/failure feedback
|
|
- 🔍 Message ID tracking
|
|
|
|
**Message Tracking**:
|
|
- Test messages marked with `metadata: { test: true }`
|
|
- Identifies sender as "admin_interface"
|
|
- Full message history in logs
|
|
- Same queue as regular messages
|
|
|
|
## Access Points
|
|
|
|
### From Gateway List
|
|
|
|
**URL**: `/admin/gateways`
|
|
|
|
Each gateway has a **Test** button in the Actions column:
|
|
- Blue button with flask icon
|
|
- Located next to Activate/Deactivate button
|
|
- Available for all gateways (online or offline)
|
|
|
|
### From Gateway Details
|
|
|
|
**URL**: `/admin/gateways/:id`
|
|
|
|
**Test Gateway** button at the bottom:
|
|
- Blue button with flask icon
|
|
- Located above Activate/Deactivate button
|
|
- Opens dedicated testing page
|
|
|
|
### Direct Testing Page
|
|
|
|
**URL**: `/admin/gateways/:id/test`
|
|
|
|
Full testing interface with:
|
|
- Connection status card
|
|
- Gateway information
|
|
- Test SMS form
|
|
- Real-time updates
|
|
|
|
## Testing Interface
|
|
|
|
### Page Layout
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ Test Gateway: [Gateway Name] │
|
|
│ [Back to Gateway Details] │
|
|
├─────────────────────────────────────────┤
|
|
│ Gateway Status │
|
|
│ ┌───────────────────────┐ │
|
|
│ │ ✅ Gateway is Online │ [Refresh] │
|
|
│ │ Last heartbeat: 30s │ │
|
|
│ └───────────────────────┘ │
|
|
├─────────────────────────────────────────┤
|
|
│ Connection Information │
|
|
│ Device ID: android-001 │
|
|
│ Name: Office Phone │
|
|
│ Priority: 5 │
|
|
│ Active: Yes │
|
|
├─────────────────────────────────────────┤
|
|
│ Send Test SMS │
|
|
│ Phone Number: [+959123456789____] │
|
|
│ Message: [This is a test___________] │
|
|
│ [________________________] │
|
|
│ 160 characters remaining │
|
|
│ │
|
|
│ [Send Test SMS] [Reset Form] │
|
|
└─────────────────────────────────────────┘
|
|
```
|
|
|
|
### Status Indicators
|
|
|
|
**Online (Green)**:
|
|
```
|
|
┌──────────────────────────────┐
|
|
│ ✅ Gateway is Online │
|
|
│ Last heartbeat: 1 minute ago │
|
|
│ 2025-10-20 13:45:30 │
|
|
└──────────────────────────────┘
|
|
```
|
|
|
|
**Offline (Red)**:
|
|
```
|
|
┌──────────────────────────────┐
|
|
│ ❌ Gateway is Offline │
|
|
│ Gateway is offline │
|
|
│ Last seen: 5 hours ago │
|
|
└──────────────────────────────┘
|
|
```
|
|
|
|
**Never Connected (Red)**:
|
|
```
|
|
┌──────────────────────────────┐
|
|
│ ❌ Gateway is Offline │
|
|
│ Gateway is offline │
|
|
│ Never connected │
|
|
└──────────────────────────────┘
|
|
```
|
|
|
|
## Using the Test Feature
|
|
|
|
### Step 1: Access Testing Page
|
|
|
|
**Option A**: From Gateway List
|
|
1. Navigate to `/admin/gateways`
|
|
2. Find the gateway you want to test
|
|
3. Click the blue **Test** button
|
|
|
|
**Option B**: From Gateway Details
|
|
1. Navigate to `/admin/gateways/:id`
|
|
2. Scroll to bottom
|
|
3. Click **Test Gateway** button
|
|
|
|
### Step 2: Check Connection Status
|
|
|
|
The page loads with automatic status check:
|
|
|
|
1. **Wait for status**: Shows loading spinner
|
|
2. **View result**: Green (online) or Red (offline)
|
|
3. **Refresh if needed**: Click **Refresh Status** button
|
|
|
|
**Connection Check Details**:
|
|
- Verifies `last_heartbeat_at` timestamp
|
|
- Must be within 2 minutes to be "online"
|
|
- Shows exact time of last heartbeat
|
|
- Displays human-readable time ago
|
|
|
|
### Step 3: Send Test SMS
|
|
|
|
1. **Enter phone number**:
|
|
- Include country code (e.g., `+959123456789`)
|
|
- Required field
|
|
- Validated on submission
|
|
|
|
2. **Enter message**:
|
|
- Default test message provided
|
|
- Customizable content
|
|
- Character counter updates live
|
|
- Warns if over 160 chars
|
|
|
|
3. **Click "Send Test SMS"**:
|
|
- Button shows spinner: "Sending..."
|
|
- Waits for response
|
|
- Displays result
|
|
|
|
4. **View result**:
|
|
|
|
**Success (Green)**:
|
|
```
|
|
┌──────────────────────────────────────┐
|
|
│ ✅ Test SMS Sent Successfully! │
|
|
│ Test SMS queued for sending │
|
|
│ Message ID: msg_abc123... │
|
|
│ Status: pending │
|
|
└──────────────────────────────────────┘
|
|
```
|
|
|
|
**Error (Red)**:
|
|
```
|
|
┌──────────────────────────────────────┐
|
|
│ ❌ Failed to Send Test SMS │
|
|
│ Phone number is not valid │
|
|
└──────────────────────────────────────┘
|
|
```
|
|
|
|
### Step 4: Verify in Logs
|
|
|
|
1. Navigate to `/admin/logs`
|
|
2. Look for test message:
|
|
- Message ID from success response
|
|
- Phone number you entered
|
|
- Status: pending → sent → delivered
|
|
3. Filter by gateway to see only this gateway's messages
|
|
|
|
## API Endpoints
|
|
|
|
### Check Connection
|
|
|
|
**Endpoint**: `POST /admin/gateways/:id/check_connection`
|
|
|
|
**Response (Online)**:
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Gateway is online",
|
|
"last_heartbeat": "2025-10-20T13:45:30.000Z",
|
|
"time_ago": "1 minute"
|
|
}
|
|
```
|
|
|
|
**Response (Offline)**:
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"message": "Gateway is offline",
|
|
"last_heartbeat": "2025-10-20T08:30:15.000Z",
|
|
"time_ago": "5 hours"
|
|
}
|
|
```
|
|
|
|
### Send Test SMS
|
|
|
|
**Endpoint**: `POST /admin/gateways/:id/send_test_sms`
|
|
|
|
**Request**:
|
|
```json
|
|
{
|
|
"phone_number": "+959123456789",
|
|
"message_body": "This is a test message"
|
|
}
|
|
```
|
|
|
|
**Response (Success)**:
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Test SMS queued for sending",
|
|
"message_id": "msg_abc123def456...",
|
|
"sms_status": "pending"
|
|
}
|
|
```
|
|
|
|
**Response (Error)**:
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"message": "Phone number and message are required"
|
|
}
|
|
```
|
|
|
|
## Routes Added
|
|
|
|
```ruby
|
|
resources :gateways do
|
|
member do
|
|
get :test # Testing page
|
|
post :check_connection # AJAX status check
|
|
post :send_test_sms # AJAX send test
|
|
post :toggle # Activate/deactivate (existing)
|
|
end
|
|
end
|
|
```
|
|
|
|
**New Routes**:
|
|
- `GET /admin/gateways/:id/test` - Testing page
|
|
- `POST /admin/gateways/:id/check_connection` - Check status
|
|
- `POST /admin/gateways/:id/send_test_sms` - Send test SMS
|
|
|
|
## Controller Actions
|
|
|
|
### `test`
|
|
```ruby
|
|
def test
|
|
@gateway = Gateway.find(params[:id])
|
|
end
|
|
```
|
|
Renders the testing page.
|
|
|
|
### `check_connection`
|
|
```ruby
|
|
def check_connection
|
|
@gateway = Gateway.find(params[:id])
|
|
|
|
if @gateway.online?
|
|
render json: {
|
|
status: "success",
|
|
message: "Gateway is online",
|
|
last_heartbeat: @gateway.last_heartbeat_at,
|
|
time_ago: helpers.time_ago_in_words(@gateway.last_heartbeat_at)
|
|
}
|
|
else
|
|
render json: {
|
|
status: "error",
|
|
message: "Gateway is offline",
|
|
last_heartbeat: @gateway.last_heartbeat_at,
|
|
time_ago: @gateway.last_heartbeat_at ? helpers.time_ago_in_words(@gateway.last_heartbeat_at) : "never"
|
|
}
|
|
end
|
|
end
|
|
```
|
|
|
|
### `send_test_sms`
|
|
```ruby
|
|
def send_test_sms
|
|
@gateway = Gateway.find(params[:id])
|
|
phone_number = params[:phone_number]
|
|
message_body = params[:message_body]
|
|
|
|
sms = SmsMessage.create!(
|
|
direction: "outbound",
|
|
phone_number: phone_number,
|
|
message_body: message_body,
|
|
gateway: @gateway,
|
|
metadata: { test: true, sent_from: "admin_interface" }
|
|
)
|
|
|
|
render json: {
|
|
status: "success",
|
|
message: "Test SMS queued for sending",
|
|
message_id: sms.message_id,
|
|
sms_status: sms.status
|
|
}
|
|
end
|
|
```
|
|
|
|
## JavaScript Features
|
|
|
|
### Auto-load Status
|
|
|
|
```javascript
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
checkConnection(); // Check on page load
|
|
});
|
|
```
|
|
|
|
### Refresh Button
|
|
|
|
```javascript
|
|
async function checkConnection() {
|
|
// Show loading
|
|
container.innerHTML = '<div class="spinner">...</div>';
|
|
|
|
// Fetch status
|
|
const response = await fetch('/admin/gateways/:id/check_connection', {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-Token': csrfToken
|
|
}
|
|
});
|
|
|
|
const data = await response.json();
|
|
// Display result
|
|
}
|
|
```
|
|
|
|
### Character Counter
|
|
|
|
```javascript
|
|
messageBody.addEventListener('input', updateCharCount);
|
|
|
|
function updateCharCount() {
|
|
const length = messageBody.value.length;
|
|
const remaining = 160 - length;
|
|
|
|
if (remaining < 0) {
|
|
const parts = Math.ceil(length / 160);
|
|
charCount.textContent = `${Math.abs(remaining)} characters over (${parts} parts)`;
|
|
charCount.classList.add('text-red-600');
|
|
} else {
|
|
charCount.textContent = `${remaining} characters remaining`;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Form Submission
|
|
|
|
```javascript
|
|
form.addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
// Disable button
|
|
submitButton.disabled = true;
|
|
submitText.innerHTML = 'Sending...';
|
|
|
|
// Send request
|
|
const response = await fetch('/admin/gateways/:id/send_test_sms', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-Token': csrfToken
|
|
},
|
|
body: JSON.stringify({
|
|
phone_number: phoneNumber.value,
|
|
message_body: messageBody.value
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
// Display result and re-enable button
|
|
});
|
|
```
|
|
|
|
## Test Message Metadata
|
|
|
|
All test messages include metadata for identification:
|
|
|
|
```ruby
|
|
{
|
|
test: true,
|
|
sent_from: "admin_interface"
|
|
}
|
|
```
|
|
|
|
**Benefits**:
|
|
- Easy to filter test messages in logs
|
|
- Distinguish from production messages
|
|
- Audit trail of admin testing
|
|
- Can be excluded from analytics
|
|
|
|
## Troubleshooting
|
|
|
|
### Connection Check Fails
|
|
|
|
**Symptom**: Can't check gateway status
|
|
|
|
**Causes**:
|
|
1. Database connection issue
|
|
2. Gateway record not found
|
|
3. JavaScript error
|
|
|
|
**Solutions**:
|
|
```bash
|
|
# Check Rails logs
|
|
tail -f log/development.log
|
|
|
|
# Verify gateway exists
|
|
bin/rails runner "puts Gateway.find(1).inspect"
|
|
|
|
# Check browser console for JavaScript errors
|
|
```
|
|
|
|
### Test SMS Not Sending
|
|
|
|
**Symptom**: SMS queued but never sent
|
|
|
|
**Causes**:
|
|
1. Gateway offline
|
|
2. Sidekiq not running
|
|
3. Redis not running
|
|
4. Queue backed up
|
|
|
|
**Solutions**:
|
|
```bash
|
|
# Check gateway status
|
|
bin/rails console
|
|
> Gateway.find(1).online?
|
|
|
|
# Check Sidekiq
|
|
ps aux | grep sidekiq
|
|
|
|
# Start Sidekiq if needed
|
|
bundle exec sidekiq
|
|
|
|
# Check Redis
|
|
redis-cli ping
|
|
```
|
|
|
|
### Invalid Phone Number
|
|
|
|
**Symptom**: "Phone number is not valid" error
|
|
|
|
**Causes**:
|
|
1. Missing country code
|
|
2. Invalid format
|
|
3. Phonelib validation failed
|
|
|
|
**Solutions**:
|
|
- Always include country code: `+959123456789`
|
|
- Check number format for your country
|
|
- Test number in console:
|
|
```ruby
|
|
Phonelib.parse("+959123456789").valid?
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
### Admin Authentication Required
|
|
|
|
- All testing endpoints require admin login
|
|
- CSRF protection enabled
|
|
- Session validation
|
|
- No public access
|
|
|
|
### Rate Limiting (Recommended)
|
|
|
|
Consider adding rate limiting:
|
|
|
|
```ruby
|
|
# config/initializers/rack_attack.rb
|
|
Rack::Attack.throttle('test_sms_per_admin', limit: 10, period: 1.hour) do |req|
|
|
if req.path == '/admin/gateways/*/send_test_sms' && req.post?
|
|
req.session[:admin_id]
|
|
end
|
|
end
|
|
```
|
|
|
|
### Test Message Limits
|
|
|
|
**Best Practices**:
|
|
- Limit test messages to prevent abuse
|
|
- Log all test SMS sends
|
|
- Monitor for unusual patterns
|
|
- Alert on excessive testing
|
|
|
|
### Phone Number Privacy
|
|
|
|
**Considerations**:
|
|
- Test messages go to real phone numbers
|
|
- Recipients will receive actual SMS
|
|
- Use dedicated test numbers
|
|
- Don't test with customer numbers
|
|
|
|
## Best Practices
|
|
|
|
### When to Use Testing
|
|
|
|
✅ **Good Use Cases**:
|
|
- After gateway registration (verify it works)
|
|
- After configuration changes
|
|
- Diagnosing offline issues
|
|
- Verifying app updates
|
|
- Training new staff
|
|
|
|
❌ **Avoid**:
|
|
- Testing with production phone numbers
|
|
- Excessive testing (generates costs)
|
|
- Testing offline gateways repeatedly
|
|
- Using for regular message sending
|
|
|
|
### Test Message Guidelines
|
|
|
|
**Recommended Content**:
|
|
```
|
|
This is a test message from MySMSAPio admin interface.
|
|
Gateway: [Gateway Name]
|
|
Date: [Date/Time]
|
|
Ignore this message.
|
|
```
|
|
|
|
**Avoid**:
|
|
- Long messages (keep under 160 chars)
|
|
- Multiple consecutive tests
|
|
- Testing during peak hours
|
|
- Sensitive information in tests
|
|
|
|
## Monitoring Test Messages
|
|
|
|
### View in Logs
|
|
|
|
1. Navigate to `/admin/logs`
|
|
2. Filter by:
|
|
- Gateway name
|
|
- Phone number
|
|
- Date range
|
|
3. Look for status progression:
|
|
- `pending` → `sent` → `delivered`
|
|
4. Check error messages if failed
|
|
|
|
### Identify Test Messages
|
|
|
|
Test messages have:
|
|
- `metadata.test = true`
|
|
- `metadata.sent_from = "admin_interface"`
|
|
|
|
**Query in console**:
|
|
```ruby
|
|
# Find all test messages
|
|
SmsMessage.where("metadata->>'test' = 'true'").count
|
|
|
|
# Find recent test messages
|
|
SmsMessage.where("metadata->>'test' = 'true'")
|
|
.where("created_at > ?", 1.day.ago)
|
|
.order(created_at: :desc)
|
|
```
|
|
|
|
## Summary
|
|
|
|
✅ **Implemented**: Gateway testing via admin interface
|
|
✅ **Features**: Connection check + Test SMS sending
|
|
✅ **Access**: From gateway list or details page
|
|
✅ **Real-time**: AJAX status updates
|
|
✅ **Tracking**: Full metadata and logging
|
|
✅ **Security**: Admin authentication required
|
|
|
|
**Test any gateway easily**:
|
|
1. Click "Test" button
|
|
2. Check status (auto-loads)
|
|
3. Send test SMS
|
|
4. View in logs
|
|
|
|
Perfect for debugging, verification, and training! 🚀
|