# Integration Example

This document shows how to integrate the AuthMiddleware and RateLimiter into your existing plugin.

## Step 1: Update Plugin.php

Add REST API registration to `includes/Core/Plugin.php`:

```php
<?php
/**
 * Main Plugin Class
 *
 * @package MultilingualPressZone
 */

declare(strict_types=1);

namespace MultilingualPressZone\Core;

if (!defined('ABSPATH')) {
    exit;
}

final class Plugin {
    // ... existing code ...

    /**
     * Initialize plugin
     */
    public function init(): void {
        // Load dependencies
        $this->load_dependencies();

        // Register hooks
        $this->register_hooks();

        // Register REST API routes
        $this->register_rest_routes();

        // Initialize admin
        if (is_admin()) {
            $this->init_admin();
        }

        // Initialize frontend
        if (!is_admin()) {
            $this->init_frontend();
        }
    }

    /**
     * Register REST API routes
     */
    private function register_rest_routes(): void {
        add_action('rest_api_init', function () {
            // Register Languages REST Controller
            $languages_controller = new \MultilingualPressZone\API\LanguagesRestController(
                $this->language_manager
            );
            $languages_controller->register_routes();

            // Register Dashboard REST Controller
            $dashboard_controller = new \MultilingualPressZone\Admin\DashboardRestController();
            $dashboard_controller->register_routes();

            // Register Jobs REST Controller
            $jobs_controller = new \MultilingualPressZone\Admin\JobsRestController();
            $jobs_controller->register_routes();
        });
    }

    // ... rest of existing code ...
}
```

## Step 2: Update Existing REST Controllers

### DashboardRestController.php

Update `includes/Admin/DashboardRestController.php`:

```php
<?php
declare(strict_types=1);

namespace MultilingualPressZone\Admin;

use MultilingualPressZone\API\AuthMiddleware;
use MultilingualPressZone\API\RateLimiter;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

if (!defined('ABSPATH')) {
    exit;
}

class DashboardRestController extends WP_REST_Controller {

    protected $namespace = 'multilingual-press-zone/v1';
    protected $rest_base = 'dashboard';

    private AuthMiddleware $auth_middleware;
    private RateLimiter $rate_limiter;

    /**
     * Constructor
     */
    public function __construct() {
        $this->auth_middleware = new AuthMiddleware();
        $this->rate_limiter = new RateLimiter();
    }

    /**
     * Register routes
     */
    public function register_routes(): void {
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/stats',
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [$this, 'get_stats'],
                'permission_callback' => [$this, 'check_permissions'],
                'args'                => [],
            ]
        );
    }

    /**
     * Get dashboard statistics
     */
    public function get_stats(WP_REST_Request $request) {
        // Check rate limit
        $identifier = $this->getRequestIdentifier($request);
        $user_id = get_current_user_id();

        if (!$this->rate_limiter->isAllowed($identifier, $user_id ?: null)) {
            return $this->rate_limiter->createErrorResponse($identifier, $user_id ?: null);
        }

        global $wpdb;

        $table_languages = $wpdb->prefix . 'mpz_languages';
        $table_translations = $wpdb->prefix . 'mpz_translations';
        $table_jobs = $wpdb->prefix . 'mpz_translation_jobs';

        // Get total languages
        $total_languages = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$table_languages} WHERE is_active = %d",
                1
            )
        );

        // Get active translations
        $active_translations = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$table_jobs} WHERE status IN (%s, %s)",
                'pending',
                'processing'
            )
        );

        // Get completed translations
        $completed_translations = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$table_jobs} WHERE status = %s",
                'completed'
            )
        );

        // Calculate completion rate
        $total_jobs = $active_translations + $completed_translations;
        $completion_rate = $total_jobs > 0 ? round(($completed_translations / $total_jobs) * 100, 1) : 0;

        // Get characters used
        $characters_used = (int) get_option('mpz_characters_used_this_month', 0);

        // Check cache status
        $cache_enabled = wp_using_ext_object_cache();

        // Check license status
        $license_valid = true;

        $response = new WP_REST_Response([
            'success' => true,
            'data'    => [
                'total_languages'      => $total_languages,
                'active_translations'  => $active_translations,
                'completion_rate'      => $completion_rate,
                'characters_used'      => $characters_used,
                'cache_enabled'        => $cache_enabled,
                'license_valid'        => $license_valid,
                'timestamp'            => current_time('mysql'),
            ],
        ], 200);

        // Add rate limit headers
        return $this->rate_limiter->addHeaders($response, $identifier, $user_id ?: null);
    }

    /**
     * Check permissions
     */
    public function check_permissions(WP_REST_Request $request) {
        if (!current_user_can('manage_options')) {
            return new WP_Error(
                'rest_forbidden',
                esc_html__('You do not have permission to access this resource.', 'multilingual-press-zone'),
                ['status' => 403]
            );
        }

        return true;
    }

    /**
     * Get request identifier for rate limiting
     */
    private function getRequestIdentifier(WP_REST_Request $request): string {
        $user_id = get_current_user_id();
        if ($user_id) {
            return 'user_' . $user_id;
        }

        // Use IP for anonymous requests
        $audit_info = $this->auth_middleware->getCurrentUserForAudit();
        return 'ip_' . ($audit_info['ip_address'] ?: 'unknown');
    }
}
```

### JobsRestController.php

Update `includes/Admin/JobsRestController.php` similarly:

```php
<?php
declare(strict_types=1);

namespace MultilingualPressZone\Admin;

use MultilingualPressZone\API\AuthMiddleware;
use MultilingualPressZone\API\RateLimiter;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

if (!defined('ABSPATH')) {
    exit;
}

class JobsRestController extends WP_REST_Controller {

    protected $namespace = 'multilingual-press-zone/v1';
    protected $rest_base = 'jobs';

    private AuthMiddleware $auth_middleware;
    private RateLimiter $rate_limiter;

    /**
     * Constructor
     */
    public function __construct() {
        $this->auth_middleware = new AuthMiddleware();
        $this->rate_limiter = new RateLimiter();
    }

    /**
     * Register routes
     */
    public function register_routes(): void {
        // GET /jobs
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base,
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [$this, 'get_jobs'],
                'permission_callback' => [$this, 'check_permissions'],
                'args'                => [
                    'recent' => [
                        'description'       => __('Limit results to recent N jobs', 'multilingual-press-zone'),
                        'type'              => 'integer',
                        'default'           => 10,
                        'minimum'           => 1,
                        'maximum'           => 100,
                        'sanitize_callback' => 'absint',
                    ],
                    'status' => [
                        'description'       => __('Filter by job status', 'multilingual-press-zone'),
                        'type'              => 'string',
                        'enum'              => ['pending', 'processing', 'completed', 'failed'],
                        'sanitize_callback' => 'sanitize_text_field',
                    ],
                ],
            ]
        );

        // GET /jobs/{id}
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/(?P<id>[\d]+)',
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [$this, 'get_job'],
                'permission_callback' => [$this, 'check_permissions'],
                'args'                => [
                    'id' => [
                        'description'       => __('Job ID', 'multilingual-press-zone'),
                        'type'              => 'integer',
                        'required'          => true,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );
    }

    /**
     * Get translation jobs
     */
    public function get_jobs(WP_REST_Request $request) {
        // Check rate limit
        $identifier = $this->getRequestIdentifier($request);
        $user_id = get_current_user_id();

        if (!$this->rate_limiter->isAllowed($identifier, $user_id ?: null)) {
            return $this->rate_limiter->createErrorResponse($identifier, $user_id ?: null);
        }

        global $wpdb;
        $table_jobs = $wpdb->prefix . 'mpz_translation_jobs';

        // Get parameters
        $recent = $request->get_param('recent');
        $status = $request->get_param('status');

        // Build query
        $query = "SELECT * FROM {$table_jobs}";
        $where_clauses = [];
        $query_args = [];

        if ($status) {
            $where_clauses[] = "status = %s";
            $query_args[] = $status;
        }

        if (!empty($where_clauses)) {
            $query .= " WHERE " . implode(' AND ', $where_clauses);
        }

        $query .= " ORDER BY created_at DESC";

        if ($recent) {
            $query .= " LIMIT %d";
            $query_args[] = $recent;
        }

        // Prepare and execute query
        if (!empty($query_args)) {
            $query = $wpdb->prepare($query, ...$query_args);
        }

        $jobs = $wpdb->get_results($query, ARRAY_A);

        if ($wpdb->last_error) {
            return new WP_Error(
                'database_error',
                esc_html__('Database error occurred while fetching jobs.', 'multilingual-press-zone'),
                ['status' => 500]
            );
        }

        // Format jobs data
        $formatted_jobs = array_map([$this, 'format_job'], $jobs);

        $response = new WP_REST_Response([
            'success' => true,
            'data'    => $formatted_jobs,
            'total'   => count($formatted_jobs),
        ], 200);

        // Add rate limit headers
        return $this->rate_limiter->addHeaders($response, $identifier, $user_id ?: null);
    }

    /**
     * Get single translation job
     */
    public function get_job(WP_REST_Request $request) {
        // Check rate limit
        $identifier = $this->getRequestIdentifier($request);
        $user_id = get_current_user_id();

        if (!$this->rate_limiter->isAllowed($identifier, $user_id ?: null)) {
            return $this->rate_limiter->createErrorResponse($identifier, $user_id ?: null);
        }

        global $wpdb;
        $job_id = $request->get_param('id');
        $table_jobs = $wpdb->prefix . 'mpz_translation_jobs';

        $job = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$table_jobs} WHERE id = %d",
                $job_id
            ),
            ARRAY_A
        );

        if (!$job) {
            return new WP_Error(
                'job_not_found',
                esc_html__('Translation job not found.', 'multilingual-press-zone'),
                ['status' => 404]
            );
        }

        $response = new WP_REST_Response([
            'success' => true,
            'data'    => $this->format_job($job),
        ], 200);

        // Add rate limit headers
        return $this->rate_limiter->addHeaders($response, $identifier, $user_id ?: null);
    }

    /**
     * Format job data
     */
    private function format_job(array $job): array {
        return [
            'id'              => (int) $job['id'],
            'content_id'      => (int) $job['content_id'],
            'content_type'    => sanitize_text_field($job['content_type'] ?? 'post'),
            'content_title'   => sanitize_text_field($job['content_title'] ?? ''),
            'source_language' => sanitize_text_field($job['source_language'] ?? 'en'),
            'target_language' => sanitize_text_field($job['target_language'] ?? ''),
            'status'          => sanitize_text_field($job['status'] ?? 'pending'),
            'progress'        => (int) ($job['progress'] ?? 0),
            'error_message'   => sanitize_text_field($job['error_message'] ?? ''),
            'created_at'      => sanitize_text_field($job['created_at'] ?? ''),
            'updated_at'      => sanitize_text_field($job['updated_at'] ?? ''),
            'completed_at'    => sanitize_text_field($job['completed_at'] ?? ''),
        ];
    }

    /**
     * Check permissions
     */
    public function check_permissions(WP_REST_Request $request) {
        if (!current_user_can('manage_options')) {
            return new WP_Error(
                'rest_forbidden',
                esc_html__('You do not have permission to access this resource.', 'multilingual-press-zone'),
                ['status' => 403]
            );
        }

        return true;
    }

    /**
     * Get request identifier for rate limiting
     */
    private function getRequestIdentifier(WP_REST_Request $request): string {
        $user_id = get_current_user_id();
        if ($user_id) {
            return 'user_' . $user_id;
        }

        // Use IP for anonymous requests
        $audit_info = $this->auth_middleware->getCurrentUserForAudit();
        return 'ip_' . ($audit_info['ip_address'] ?: 'unknown');
    }
}
```

## Step 3: Test the Integration

### Via Browser (with REST API Console or Postman)

1. Test without authentication:
```
GET http://your-site.local/wp-json/multilingual-press-zone/v1/languages
```

2. Test with authentication:
```
GET http://your-site.local/wp-json/multilingual-press-zone/v1/languages
Headers:
  X-WP-Nonce: [get from wp.rest.nonce in browser console]
```

3. Test rate limiting:
```bash
# Run this in a loop to trigger rate limit
for i in {1..15}; do
  curl -i http://your-site.local/wp-json/multilingual-press-zone/v1/languages
done
```

### Via wp-cli

Run the test script:
```bash
cd /path/to/wordpress
wp eval-file wp-content/plugins/multilingual-press-zone/includes/API/test-rate-limiting.php
```

## Step 4: Monitor and Adjust

Add logging to track rate limit violations:

```php
// In RateLimiter::isAllowed()
if ($count >= $limit) {
    error_log(sprintf(
        'MPZ Rate Limit: %s exceeded limit (%d/%d) - User ID: %s',
        $identifier,
        $count,
        $limit,
        $userId ?? 'anonymous'
    ));
    return false;
}
```

Check WordPress error logs:
```bash
tail -f /path/to/wordpress/wp-content/debug.log | grep "MPZ Rate Limit"
```

## Summary

You've now:
1. ✅ Created AuthMiddleware for centralized authentication
2. ✅ Created RateLimiter for API abuse prevention
3. ✅ Updated Plugin.php to register REST routes
4. ✅ Updated existing REST controllers to use rate limiting
5. ✅ Added testing capabilities
6. ✅ Added monitoring and logging

Your REST API is now protected with:
- Rate limiting (10/60/300 req/min)
- Permission checks
- Audit logging
- Standard rate limit headers
- Proper error responses
