This commit adds comprehensive mobile app support to enable a native Android app that won't timeout or sleep when the screen goes dark.
New Features:
- JWT-based authentication system (no WordPress session dependency)
- REST API endpoints for mobile app (agent status, queue management, call control)
- Server-Sent Events (SSE) for real-time updates to mobile app
- Firebase Cloud Messaging (FCM) integration for push notifications
- Gitea-based automatic plugin updates
- Mobile app admin settings page
New Files:
- includes/class-twp-mobile-auth.php - JWT authentication with login/refresh/logout
- includes/class-twp-mobile-api.php - REST API endpoints under /twilio-mobile/v1
- includes/class-twp-mobile-sse.php - Real-time event streaming
- includes/class-twp-fcm.php - Push notification handling
- includes/class-twp-auto-updater.php - Gitea-based auto-updates
- admin/mobile-app-settings.php - Admin configuration page
Modified Files:
- includes/class-twp-activator.php - Added twp_mobile_sessions table
- includes/class-twp-core.php - Load and initialize mobile classes
- admin/class-twp-admin.php - Added Mobile App menu item and settings page
Database Changes:
- New table: twp_mobile_sessions (stores JWT refresh tokens and FCM tokens)
API Endpoints:
- POST /twilio-mobile/v1/auth/login
- POST /twilio-mobile/v1/auth/refresh
- POST /twilio-mobile/v1/auth/logout
- GET/POST /twilio-mobile/v1/agent/status
- GET /twilio-mobile/v1/queues/state
- POST /twilio-mobile/v1/calls/{call_sid}/accept
- GET /twilio-mobile/v1/stream/events (SSE)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
354 lines
15 KiB
PHP
354 lines
15 KiB
PHP
<?php
|
|
/**
|
|
* Mobile App Settings Page
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if (!defined('WPINC')) {
|
|
die;
|
|
}
|
|
|
|
// Check user capabilities
|
|
if (!current_user_can('manage_options')) {
|
|
wp_die(__('You do not have sufficient permissions to access this page.'));
|
|
}
|
|
|
|
// Handle manual update check
|
|
if (isset($_POST['twp_check_updates']) && check_admin_referer('twp_mobile_settings')) {
|
|
require_once TWP_PLUGIN_DIR . 'includes/class-twp-auto-updater.php';
|
|
$updater = new TWP_Auto_Updater();
|
|
$update_result = $updater->manual_check_for_updates();
|
|
}
|
|
|
|
// Handle test notification
|
|
if (isset($_POST['twp_test_notification']) && check_admin_referer('twp_mobile_settings')) {
|
|
require_once TWP_PLUGIN_DIR . 'includes/class-twp-fcm.php';
|
|
$fcm = new TWP_FCM();
|
|
$test_user_id = get_current_user_id();
|
|
$notification_sent = $fcm->send_test_notification($test_user_id);
|
|
|
|
if ($notification_sent) {
|
|
$notification_result = array('success' => true, 'message' => 'Test notification sent successfully!');
|
|
} else {
|
|
$notification_result = array('success' => false, 'message' => 'Failed to send test notification. Check FCM configuration.');
|
|
}
|
|
}
|
|
|
|
// Save settings
|
|
if (isset($_POST['twp_save_mobile_settings']) && check_admin_referer('twp_mobile_settings')) {
|
|
update_option('twp_fcm_server_key', sanitize_text_field($_POST['twp_fcm_server_key']));
|
|
update_option('twp_auto_update_enabled', isset($_POST['twp_auto_update_enabled']) ? '1' : '0');
|
|
update_option('twp_gitea_repo', sanitize_text_field($_POST['twp_gitea_repo']));
|
|
update_option('twp_gitea_token', sanitize_text_field($_POST['twp_gitea_token']));
|
|
|
|
$settings_saved = true;
|
|
}
|
|
|
|
// Get current settings
|
|
$fcm_server_key = get_option('twp_fcm_server_key', '');
|
|
$auto_update_enabled = get_option('twp_auto_update_enabled', '1') === '1';
|
|
$gitea_repo = get_option('twp_gitea_repo', 'wp-plugins/twilio-wp-plugin');
|
|
$gitea_token = get_option('twp_gitea_token', '');
|
|
|
|
// Get update status
|
|
require_once TWP_PLUGIN_DIR . 'includes/class-twp-auto-updater.php';
|
|
$updater = new TWP_Auto_Updater();
|
|
$update_status = $updater->get_update_status();
|
|
|
|
// Get mobile app statistics
|
|
global $wpdb;
|
|
$sessions_table = $wpdb->prefix . 'twp_mobile_sessions';
|
|
$active_sessions = $wpdb->get_var("SELECT COUNT(*) FROM $sessions_table WHERE is_active = 1 AND expires_at > NOW()");
|
|
$total_sessions = $wpdb->get_var("SELECT COUNT(*) FROM $sessions_table");
|
|
|
|
?>
|
|
|
|
<div class="wrap">
|
|
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
|
|
|
|
<?php if (isset($settings_saved)): ?>
|
|
<div class="notice notice-success is-dismissible">
|
|
<p><strong>Settings saved successfully!</strong></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (isset($update_result)): ?>
|
|
<div class="notice notice-<?php echo $update_result['update_available'] ? 'warning' : 'success'; ?> is-dismissible">
|
|
<p><strong><?php echo esc_html($update_result['message']); ?></strong></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (isset($notification_result)): ?>
|
|
<div class="notice notice-<?php echo $notification_result['success'] ? 'success' : 'error'; ?> is-dismissible">
|
|
<p><strong><?php echo esc_html($notification_result['message']); ?></strong></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="twp-mobile-settings">
|
|
<!-- Mobile App Overview -->
|
|
<div class="card" style="max-width: 100%; margin-bottom: 20px;">
|
|
<h2>Mobile App Overview</h2>
|
|
<table class="widefat">
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>API Endpoint:</strong></td>
|
|
<td><code><?php echo esc_html(site_url('/wp-json/twilio-mobile/v1')); ?></code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Active Sessions:</strong></td>
|
|
<td><?php echo esc_html($active_sessions); ?> active / <?php echo esc_html($total_sessions); ?> total</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Plugin Version:</strong></td>
|
|
<td><?php echo esc_html(TWP_VERSION); ?></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Mobile App Settings Form -->
|
|
<form method="post" action="">
|
|
<?php wp_nonce_field('twp_mobile_settings'); ?>
|
|
|
|
<!-- FCM Configuration -->
|
|
<div class="card" style="max-width: 100%; margin-bottom: 20px;">
|
|
<h2>Firebase Cloud Messaging (FCM)</h2>
|
|
<p>Configure FCM to enable push notifications for the mobile app.</p>
|
|
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="twp_fcm_server_key">FCM Server Key</label>
|
|
</th>
|
|
<td>
|
|
<input type="text"
|
|
id="twp_fcm_server_key"
|
|
name="twp_fcm_server_key"
|
|
value="<?php echo esc_attr($fcm_server_key); ?>"
|
|
class="regular-text"
|
|
placeholder="AAAA...">
|
|
<p class="description">
|
|
Get your server key from Firebase Console > Project Settings > Cloud Messaging > Server Key
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<?php if (!empty($fcm_server_key)): ?>
|
|
<p>
|
|
<button type="submit" name="twp_test_notification" class="button">
|
|
Send Test Notification
|
|
</button>
|
|
<span class="description">Send a test notification to your devices</span>
|
|
</p>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Auto-Update Settings -->
|
|
<div class="card" style="max-width: 100%; margin-bottom: 20px;">
|
|
<h2>Automatic Updates</h2>
|
|
|
|
<table class="form-table">
|
|
<tr>
|
|
<th scope="row">Current Version</th>
|
|
<td>
|
|
<strong><?php echo esc_html($update_status['current_version']); ?></strong>
|
|
<?php if ($update_status['update_available']): ?>
|
|
<span style="color: #d63638; margin-left: 10px;">
|
|
⚠ Update available: <?php echo esc_html($update_status['latest_version']); ?>
|
|
</span>
|
|
<?php else: ?>
|
|
<span style="color: #00a32a; margin-left: 10px;">✓ Up to date</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="twp_auto_update_enabled">Enable Auto-Updates</label>
|
|
</th>
|
|
<td>
|
|
<label>
|
|
<input type="checkbox"
|
|
id="twp_auto_update_enabled"
|
|
name="twp_auto_update_enabled"
|
|
value="1"
|
|
<?php checked($auto_update_enabled); ?>>
|
|
Automatically check for updates every 12 hours
|
|
</label>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="twp_gitea_repo">Gitea Repository</label>
|
|
</th>
|
|
<td>
|
|
<input type="text"
|
|
id="twp_gitea_repo"
|
|
name="twp_gitea_repo"
|
|
value="<?php echo esc_attr($gitea_repo); ?>"
|
|
class="regular-text"
|
|
placeholder="org/repo-name">
|
|
<p class="description">
|
|
Format: organization/repository (e.g., wp-plugins/twilio-wp-plugin)
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">
|
|
<label for="twp_gitea_token">Gitea Access Token</label>
|
|
</th>
|
|
<td>
|
|
<input type="password"
|
|
id="twp_gitea_token"
|
|
name="twp_gitea_token"
|
|
value="<?php echo esc_attr($gitea_token); ?>"
|
|
class="regular-text"
|
|
placeholder="">
|
|
<p class="description">
|
|
Optional. Required only for private repositories. Create token at:
|
|
<a href="https://repo.anhonesthost.net/user/settings/applications" target="_blank">Gitea Settings > Applications</a>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th scope="row">Last Update Check</th>
|
|
<td>
|
|
<?php
|
|
$last_check = $update_status['last_check'];
|
|
if ($last_check > 0) {
|
|
echo esc_html(human_time_diff($last_check, current_time('timestamp')) . ' ago');
|
|
} else {
|
|
echo 'Never';
|
|
}
|
|
?>
|
|
<button type="submit" name="twp_check_updates" class="button" style="margin-left: 15px;">
|
|
Check Now
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- API Documentation -->
|
|
<div class="card" style="max-width: 100%; margin-bottom: 20px;">
|
|
<h2>API Endpoints</h2>
|
|
<p>Available REST API endpoints for mobile app development:</p>
|
|
|
|
<table class="widefat striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Endpoint</th>
|
|
<th>Method</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>/twilio-mobile/v1/auth/login</code></td>
|
|
<td>POST</td>
|
|
<td>Authenticate and get JWT tokens</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/twilio-mobile/v1/auth/refresh</code></td>
|
|
<td>POST</td>
|
|
<td>Refresh access token</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/twilio-mobile/v1/agent/status</code></td>
|
|
<td>GET/POST</td>
|
|
<td>Get or update agent status</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/twilio-mobile/v1/queues/state</code></td>
|
|
<td>GET</td>
|
|
<td>Get all queue states</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/twilio-mobile/v1/calls/{call_sid}/accept</code></td>
|
|
<td>POST</td>
|
|
<td>Accept a queued call</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/twilio-mobile/v1/stream/events</code></td>
|
|
<td>GET</td>
|
|
<td>Server-Sent Events stream for real-time updates</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<p style="margin-top: 15px;">
|
|
<strong>Authentication:</strong> All endpoints (except login/refresh) require
|
|
<code>Authorization: Bearer <access_token></code> header.
|
|
</p>
|
|
</div>
|
|
|
|
<p class="submit">
|
|
<button type="submit" name="twp_save_mobile_settings" class="button button-primary">
|
|
Save Settings
|
|
</button>
|
|
</p>
|
|
</form>
|
|
|
|
<!-- Active Sessions -->
|
|
<?php if ($active_sessions > 0): ?>
|
|
<div class="card" style="max-width: 100%; margin-bottom: 20px;">
|
|
<h2>Active Mobile Sessions</h2>
|
|
<?php
|
|
$sessions = $wpdb->get_results("
|
|
SELECT s.user_id, s.device_info, s.logged_in_at, s.last_used, u.user_login, u.display_name
|
|
FROM $sessions_table s
|
|
JOIN {$wpdb->users} u ON s.user_id = u.ID
|
|
WHERE s.is_active = 1 AND s.expires_at > NOW()
|
|
ORDER BY s.last_used DESC
|
|
LIMIT 20
|
|
");
|
|
?>
|
|
<table class="widefat striped">
|
|
<thead>
|
|
<tr>
|
|
<th>User</th>
|
|
<th>Device</th>
|
|
<th>Last Activity</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($sessions as $session): ?>
|
|
<tr>
|
|
<td><?php echo esc_html($session->display_name ?: $session->user_login); ?></td>
|
|
<td><?php echo esc_html($session->device_info ?: 'Unknown device'); ?></td>
|
|
<td><?php echo esc_html(human_time_diff(strtotime($session->last_used), current_time('timestamp')) . ' ago'); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.twp-mobile-settings .card {
|
|
padding: 20px;
|
|
background: #fff;
|
|
border: 1px solid #ccd0d4;
|
|
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
|
}
|
|
|
|
.twp-mobile-settings .card h2 {
|
|
margin-top: 0;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid #f0f0f1;
|
|
}
|
|
|
|
.twp-mobile-settings code {
|
|
background: #f0f0f1;
|
|
padding: 2px 6px;
|
|
border-radius: 3px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.twp-mobile-settings table.widefat td code {
|
|
background: #f6f7f7;
|
|
}
|
|
</style>
|