This update adds two major features: 1. Queue Timeout Voicemail - Callers can now leave voicemail when queue timeout is reached - Configurable per-queue voicemail prompts with TTS support - Automatic transcription and urgent keyword detection - Admin setting to choose between voicemail or callback on timeout 2. Amazon SNS SMS Provider - Alternative SMS provider to Twilio for sending text messages - Useful when Twilio SMS approval is difficult to obtain - Provider abstraction layer allows switching between Twilio/SNS - Full AWS SNS configuration in admin settings - Supports custom sender IDs in compatible countries - Lower cost per SMS compared to Twilio New Files: - includes/class-twp-voicemail-handler.php - Voicemail recording handler - includes/interface-twp-sms-provider.php - SMS provider interface - includes/class-twp-sms-provider-twilio.php - Twilio SMS implementation - includes/class-twp-sms-provider-sns.php - Amazon SNS implementation - includes/class-twp-sms-manager.php - SMS provider abstraction manager - QUEUE_VOICEMAIL_SMS_FEATURES.md - Complete feature documentation Modified Files: - includes/class-twp-call-queue.php - Added voicemail option to timeout handler - includes/class-twp-twilio-api.php - Updated send_sms() to use provider abstraction - admin/class-twp-admin.php - Added SMS provider and timeout action settings - composer.json - Added AWS SDK dependency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			207 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * Amazon SNS SMS Provider
 | 
						|
 *
 | 
						|
 * SMS provider implementation for Amazon SNS/SMS
 | 
						|
 */
 | 
						|
class TWP_SMS_Provider_SNS implements TWP_SMS_Provider {
 | 
						|
 | 
						|
    private $sns_client;
 | 
						|
    private $default_sender_id;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructor
 | 
						|
     */
 | 
						|
    public function __construct() {
 | 
						|
        $aws_access_key = get_option('twp_aws_access_key');
 | 
						|
        $aws_secret_key = get_option('twp_aws_secret_key');
 | 
						|
        $aws_region = get_option('twp_aws_region', 'us-east-1');
 | 
						|
        $this->default_sender_id = get_option('twp_aws_sns_sender_id', '');
 | 
						|
 | 
						|
        // Initialize AWS SNS client if credentials are available
 | 
						|
        if (!empty($aws_access_key) && !empty($aws_secret_key)) {
 | 
						|
            try {
 | 
						|
                // Check if AWS SDK is available
 | 
						|
                if (!class_exists('Aws\Sns\SnsClient')) {
 | 
						|
                    error_log('TWP SNS Error: AWS SDK not found. Please install via Composer: composer require aws/aws-sdk-php');
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
 | 
						|
                $this->sns_client = new Aws\Sns\SnsClient([
 | 
						|
                    'version' => 'latest',
 | 
						|
                    'region' => $aws_region,
 | 
						|
                    'credentials' => [
 | 
						|
                        'key' => $aws_access_key,
 | 
						|
                        'secret' => $aws_secret_key
 | 
						|
                    ]
 | 
						|
                ]);
 | 
						|
            } catch (Exception $e) {
 | 
						|
                error_log('TWP SNS Error: Failed to initialize SNS client: ' . $e->getMessage());
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Send an SMS message
 | 
						|
     *
 | 
						|
     * @param string $to_number Recipient phone number (E.164 format)
 | 
						|
     * @param string $message Message body
 | 
						|
     * @param string $from_number Sender phone number or Sender ID (not used by SNS in the same way)
 | 
						|
     * @return array Response array with 'success' and 'data' or 'error'
 | 
						|
     */
 | 
						|
    public function send_sms($to_number, $message, $from_number = null) {
 | 
						|
        try {
 | 
						|
            if (!$this->sns_client) {
 | 
						|
                return [
 | 
						|
                    'success' => false,
 | 
						|
                    'error' => 'AWS SNS client not initialized. Check AWS credentials and ensure AWS SDK is installed.'
 | 
						|
                ];
 | 
						|
            }
 | 
						|
 | 
						|
            // Prepare message attributes
 | 
						|
            $message_attributes = [
 | 
						|
                'AWS.SNS.SMS.SMSType' => [
 | 
						|
                    'DataType' => 'String',
 | 
						|
                    'StringValue' => 'Transactional' // Transactional for higher reliability
 | 
						|
                ]
 | 
						|
            ];
 | 
						|
 | 
						|
            // Use sender ID if provided or use default
 | 
						|
            $sender_id = $from_number ?: $this->default_sender_id;
 | 
						|
            if (!empty($sender_id)) {
 | 
						|
                // Remove '+' and non-alphanumeric characters for Sender ID
 | 
						|
                // Note: Sender ID is alphanumeric (3-11 chars) in many countries
 | 
						|
                $sender_id_clean = preg_replace('/[^a-zA-Z0-9]/', '', $sender_id);
 | 
						|
                if (strlen($sender_id_clean) >= 3 && strlen($sender_id_clean) <= 11) {
 | 
						|
                    $message_attributes['AWS.SNS.SMS.SenderID'] = [
 | 
						|
                        'DataType' => 'String',
 | 
						|
                        'StringValue' => $sender_id_clean
 | 
						|
                    ];
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // Send SMS via SNS
 | 
						|
            $result = $this->sns_client->publish([
 | 
						|
                'Message' => $message,
 | 
						|
                'PhoneNumber' => $to_number,
 | 
						|
                'MessageAttributes' => $message_attributes
 | 
						|
            ]);
 | 
						|
 | 
						|
            return [
 | 
						|
                'success' => true,
 | 
						|
                'provider' => 'aws_sns',
 | 
						|
                'data' => [
 | 
						|
                    'message_id' => $result['MessageId'],
 | 
						|
                    'to' => $to_number,
 | 
						|
                    'body' => $message,
 | 
						|
                    'sender_id' => !empty($sender_id_clean) ? $sender_id_clean : null
 | 
						|
                ]
 | 
						|
            ];
 | 
						|
        } catch (Aws\Exception\AwsException $e) {
 | 
						|
            return [
 | 
						|
                'success' => false,
 | 
						|
                'provider' => 'aws_sns',
 | 
						|
                'error' => $e->getAwsErrorMessage(),
 | 
						|
                'code' => $e->getAwsErrorCode()
 | 
						|
            ];
 | 
						|
        } catch (Exception $e) {
 | 
						|
            return [
 | 
						|
                'success' => false,
 | 
						|
                'provider' => 'aws_sns',
 | 
						|
                'error' => $e->getMessage()
 | 
						|
            ];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get provider name
 | 
						|
     *
 | 
						|
     * @return string Provider name
 | 
						|
     */
 | 
						|
    public function get_provider_name() {
 | 
						|
        return 'Amazon SNS';
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Validate provider configuration
 | 
						|
     *
 | 
						|
     * @return array Response array with 'success' and 'message' or 'error'
 | 
						|
     */
 | 
						|
    public function validate_configuration() {
 | 
						|
        // Check if AWS SDK is available
 | 
						|
        if (!class_exists('Aws\Sns\SnsClient')) {
 | 
						|
            return [
 | 
						|
                'success' => false,
 | 
						|
                'error' => 'AWS SDK not installed. Please run: composer require aws/aws-sdk-php'
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        $aws_access_key = get_option('twp_aws_access_key');
 | 
						|
        $aws_secret_key = get_option('twp_aws_secret_key');
 | 
						|
        $aws_region = get_option('twp_aws_region');
 | 
						|
 | 
						|
        if (empty($aws_access_key)) {
 | 
						|
            return [
 | 
						|
                'success' => false,
 | 
						|
                'error' => 'AWS Access Key is not configured'
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        if (empty($aws_secret_key)) {
 | 
						|
            return [
 | 
						|
                'success' => false,
 | 
						|
                'error' => 'AWS Secret Key is not configured'
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        if (empty($aws_region)) {
 | 
						|
            return [
 | 
						|
                'success' => false,
 | 
						|
                'error' => 'AWS Region is not configured'
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        if (!$this->sns_client) {
 | 
						|
            return [
 | 
						|
                'success' => false,
 | 
						|
                'error' => 'Failed to initialize AWS SNS client'
 | 
						|
            ];
 | 
						|
        }
 | 
						|
 | 
						|
        return [
 | 
						|
            'success' => true,
 | 
						|
            'message' => 'Amazon SNS SMS provider is properly configured'
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set SMS spending limit (optional administrative function)
 | 
						|
     *
 | 
						|
     * @param float $monthly_limit Monthly spending limit in USD
 | 
						|
     * @return array Response array
 | 
						|
     */
 | 
						|
    public function set_spending_limit($monthly_limit) {
 | 
						|
        try {
 | 
						|
            if (!$this->sns_client) {
 | 
						|
                return ['success' => false, 'error' => 'SNS client not initialized'];
 | 
						|
            }
 | 
						|
 | 
						|
            $this->sns_client->setSMSAttributes([
 | 
						|
                'attributes' => [
 | 
						|
                    'MonthlySpendLimit' => (string)$monthly_limit
 | 
						|
                ]
 | 
						|
            ]);
 | 
						|
 | 
						|
            return [
 | 
						|
                'success' => true,
 | 
						|
                'message' => "SMS spending limit set to \$$monthly_limit per month"
 | 
						|
            ];
 | 
						|
        } catch (Exception $e) {
 | 
						|
            return [
 | 
						|
                'success' => false,
 | 
						|
                'error' => $e->getMessage()
 | 
						|
            ];
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |