Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.58% covered (warning)
89.58%
43 / 48
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
Retention_Bridge
93.48% covered (success)
93.48%
43 / 46
50.00% covered (danger)
50.00%
1 / 2
9.02
0.00% covered (danger)
0.00%
0 / 1
 register_routes
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 update_retention
89.66% covered (warning)
89.66%
26 / 29
0.00% covered (danger)
0.00%
0 / 1
8.07
1<?php
2/**
3 * Retention REST bridge — changes how many days of backups WordPress.com keeps.
4 *
5 * @package automattic/jetpack-backup-plugin
6 */
7
8namespace Automattic\Jetpack\Backup\V0005\REST;
9
10use Automattic\Jetpack\Connection\Client;
11use WP_Error;
12use WP_REST_Request;
13use WP_REST_Server;
14
15if ( ! defined( 'ABSPATH' ) ) {
16    exit( 0 );
17}
18
19/**
20 * Writes the retention period. The read is `retention_days` on the legacy `/site/backup/size`.
21 */
22class Retention_Bridge {
23
24    /**
25     * The periods Jetpack Cloud offers. WordPress.com also accepts 2, which only its own downgrade sets.
26     *
27     * @var int[]
28     */
29    const RETENTION_DAYS = array( 7, 30, 120, 365 );
30
31    /**
32     * Register the POST /jetpack/v4/site/backup/retention route.
33     *
34     * @return void
35     */
36    public static function register_routes() {
37        register_rest_route(
38            'jetpack/v4',
39            '/site/backup/retention',
40            array(
41                'methods'             => WP_REST_Server::CREATABLE,
42                'callback'            => array( __CLASS__, 'update_retention' ),
43                'permission_callback' => array( Rest_Controller::class, 'permission_check' ),
44                'args'                => array(
45                    'retention_days' => array(
46                        'description' => __( 'Days of backups to keep.', 'jetpack-backup-pkg' ),
47                        'type'        => 'integer',
48                        'required'    => true,
49                        'enum'        => self::RETENTION_DAYS,
50                    ),
51                ),
52            )
53        );
54    }
55
56    /**
57     * Proxy `POST /sites/{id}/backup/retention/update` (v2). It refuses blog tokens, so this signs as the user.
58     *
59     * @param WP_REST_Request $request The request.
60     * @return \WP_REST_Response|WP_Error The new retention, or WP_Error on failure.
61     */
62    public static function update_retention( WP_REST_Request $request ) {
63        $blog_id = Rest_Controller::get_blog_id_or_error();
64        if ( is_wp_error( $blog_id ) ) {
65            return $blog_id;
66        }
67
68        $days = (int) $request->get_param( 'retention_days' );
69
70        $response = Client::wpcom_json_api_request_as_user(
71            sprintf( '/sites/%d/backup/retention/update', $blog_id ),
72            'v2',
73            array( 'method' => 'POST' ),
74            array( 'retention_days' => $days ),
75            'wpcom'
76        );
77
78        if ( is_wp_error( $response ) ) {
79            return Rest_Controller::transport_error( $response, 'retention_update_failed' );
80        }
81
82        $message = __( 'Could not change how long backups are kept.', 'jetpack-backup-pkg' );
83
84        if ( 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
85            return Rest_Controller::upstream_error( $response, 'retention_update_failed', $message );
86        }
87
88        $decoded = json_decode( wp_remote_retrieve_body( $response ), true );
89
90        // A VaultPress refusal arrives as a 200 with `success: false`.
91        if ( ! is_array( $decoded ) || empty( $decoded['success'] ) ) {
92            $data   = array( 'status' => 500 );
93            $reason = Rest_Controller::upstream_reason( is_array( $decoded ) ? $decoded : array() );
94            if ( ! empty( $reason ) ) {
95                $data['wpcom'] = $reason;
96            }
97
98            return new WP_Error( 'retention_update_failed', $message, $data );
99        }
100
101        return rest_ensure_response(
102            array(
103                'ok'             => true,
104                'retention_days' => $days,
105            )
106        );
107    }
108}