Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
81.82% covered (warning)
81.82%
36 / 44
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Notices_Controller
81.82% covered (warning)
81.82%
36 / 44
50.00% covered (danger)
50.00%
3 / 6
6.22
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 register
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 register_routes
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
1 / 1
1
 check_permission
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_notices
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 update_notice
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * REST controller for the dashboard notices, which need local processing the data proxy can't do.
4 *
5 * @package automattic/jetpack-premium-analytics
6 */
7
8namespace Automattic\Jetpack\PremiumAnalytics\REST;
9
10use Automattic\Jetpack\PremiumAnalytics\Capabilities;
11use Automattic\Jetpack\PremiumAnalytics\Notices;
12use WP_REST_Request;
13use WP_REST_Server;
14
15/**
16 * Exposes `jetpack-premium-analytics/v1/notices` (GET + POST).
17 *
18 * Unlike the transparent endpoints served by {@see Api_Proxy_Controller}, the notices GET augments
19 * the WPCOM dismissal state with locally-derived flags (opt-in/opt-out/feedback/GDPR), so it lives
20 * on its own route outside `proxy/` and delegates to the {@see Notices} class.
21 */
22class Notices_Controller {
23
24    /**
25     * Package slug, used as the REST namespace root.
26     *
27     * @var string
28     */
29    private const SLUG = 'jetpack-premium-analytics';
30
31    /**
32     * REST namespace.
33     *
34     * @var string
35     */
36    private $namespace;
37
38    /**
39     * Constructor.
40     */
41    public function __construct() {
42        $this->namespace = self::SLUG . '/v1';
43    }
44
45    /**
46     * Hook the controller's routes onto rest_api_init.
47     *
48     * @return void
49     */
50    public static function register(): void {
51        $controller = new self();
52        add_action( 'rest_api_init', array( $controller, 'register_routes' ) );
53    }
54
55    /**
56     * Register the notices route.
57     *
58     * @return void
59     */
60    public function register_routes(): void {
61        register_rest_route(
62            $this->namespace,
63            '/notices',
64            array(
65                array(
66                    'methods'             => WP_REST_Server::READABLE,
67                    'callback'            => array( $this, 'get_notices' ),
68                    'permission_callback' => array( $this, 'check_permission' ),
69                ),
70                array(
71                    'methods'             => WP_REST_Server::EDITABLE,
72                    'callback'            => array( $this, 'update_notice' ),
73                    'permission_callback' => array( $this, 'check_permission' ),
74                    'args'                => array(
75                        'id'            => array(
76                            'required'    => true,
77                            'type'        => 'string',
78                            'description' => __( 'ID of the notice.', 'jetpack-premium-analytics-pkg' ),
79                        ),
80                        'status'        => array(
81                            'required'    => true,
82                            'type'        => 'string',
83                            'description' => __( 'Status of the notice.', 'jetpack-premium-analytics-pkg' ),
84                        ),
85                        'postponed_for' => array(
86                            'type'        => 'number',
87                            'default'     => 0,
88                            'description' => __( 'Postponed for (in seconds).', 'jetpack-premium-analytics-pkg' ),
89                            'minimum'     => 0,
90                        ),
91                    ),
92                ),
93            )
94        );
95    }
96
97    /**
98     * Whether the current user may read or change the dashboard notices.
99     *
100     * @return bool
101     */
102    public function check_permission(): bool {
103        return Capabilities::current_user_can_view_analytics();
104    }
105
106    /**
107     * Get the notices to show, with locally-derived flags merged in.
108     *
109     * @param WP_REST_Request $request Request object.
110     *
111     * @return array
112     */
113    public function get_notices( WP_REST_Request $request ): array {
114        return ( new Notices() )->get_notices_to_show( null !== $request->get_param( 'force_refresh' ) );
115    }
116
117    /**
118     * Dismiss or delay a notice.
119     *
120     * @param WP_REST_Request $request Request object.
121     *
122     * @return array|\WP_Error
123     */
124    public function update_notice( WP_REST_Request $request ) {
125        return ( new Notices() )->update_notice(
126            $request->get_param( 'id' ),
127            $request->get_param( 'status' ),
128            $request->get_param( 'postponed_for' )
129        );
130    }
131}