Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
WordPress
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 9
240
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 init
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_description
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 handle_ses_bounce
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 handle_ses_complaint
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setup_test
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 verify_test
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 delete_test_data
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Functionality to mark WordPress user accounts as Bounced Email.
4 *
5 * @link       https://BrianHenry.ie
6 * @since      1.1.0
7 *
8 * @package brianhenryie/bh-wp-aws-ses-bounce-handler
9 */
10
11namespace BrianHenryIE\AWS_SES_Bounce_Handler\API\Integrations;
12
13use BrianHenryIE\AWS_SES_Bounce_Handler\Admin\Bounce_Handler_Test;
14use BrianHenryIE\AWS_SES_Bounce_Handler\API\SES_Bounce_Handler_Integration_Interface;
15use Psr\Log\LoggerAwareTrait;
16use Psr\Log\LoggerInterface;
17use stdClass;
18use WP_User;
19
20/**
21 * Hook into `handle_ses_bounce` to add Bounced Email role it to user accounts.
22 *
23 * Class WordPress
24 *
25 * @package brianhenryie/bh-wp-aws-ses-bounce-handler
26 */
27class WordPress implements SES_Bounce_Handler_Integration_Interface {
28
29    use LoggerAwareTrait;
30
31    /**
32     * Constructor.
33     *
34     * @param LoggerInterface $logger A PSR logger.
35     */
36    public function __construct( LoggerInterface $logger ) {
37        $this->setLogger( $logger );
38    }
39
40    /**
41     * The WordPress integration can always be enabled since it does not depend on external classes.
42     * It can still be removed in the `bh_wp_aws_ses_bounce_handler_integrations` filter.
43     *
44     * @return bool
45     */
46    public function is_enabled(): bool {
47        return true;
48    }
49
50    /**
51     * Nothing needed.
52     */
53    public function init(): void {
54    }
55
56    /**
57     * Describe the effect of the integration: a new user role is added ot bounced accounts.
58     *
59     * @return string
60     */
61    public function get_description(): string {
62        return 'Adds <a href="' . esc_url( admin_url( 'users.php?role=bounced_email' ) ) . '">Bounced Email</a> role to users';
63    }
64
65    /**
66     * Add Bounced Email role to user so it can be filtered on the Users admin page.
67     *
68     * @hooked handle_ses_bounce
69     *
70     * @param string   $email_address     The email address that has bounced.
71     * @param stdClass $bounced_recipient Parent object with emailAddress, status, action, diagnosticCode.
72     * @param stdClass $message           Parent object of complete notification.
73     */
74    public function handle_ses_bounce( string $email_address, stdClass $bounced_recipient, stdClass $message ): void {
75
76        $this->logger->debug( __CLASS__ . __FUNCTION__ . $email_address );
77
78        $user = get_user_by( 'email', $email_address );
79
80        if ( ! $user ) {
81            $this->logger->info( 'user not found for email : ' . $email_address );
82            return;
83        }
84
85        $user->add_role( 'bounced_email' );
86
87        $this->logger->info( 'Added bounced_email role to `wp_user:' . $user->ID . '`' );
88    }
89
90    /**
91     * Do nothing.
92     *
93     * @hooked handle_ses_complaint
94     *
95     * @param string   $email_address The email address which complained about our email.
96     * @param stdClass $complained_recipient The SES notification the email address was received in.
97     * @param stdClass $message The SNS notification the SES notification was received in.
98     */
99    public function handle_ses_complaint( string $email_address, stdClass $complained_recipient, stdClass $message ): void {
100    }
101
102    /**
103     * Create a WordPress user with the AWS SES bounce simulator email address.
104     *
105     * @param Bounce_Handler_Test $test The test configuration.
106     *
107     * @return array{data:array{wp_user_id:int,wp_user_roles:string|string[]}, html:string} The values to save, html to print.
108     */
109    public function setup_test( Bounce_Handler_Test $test ): ?array {
110
111        $test_data = array();
112
113        $user_id = wp_create_user( $test->get_email(), wp_generate_password( 30 ), $test->get_email() );
114
115        if ( is_wp_error( $user_id ) ) {
116            return null;
117        }
118
119        $user = get_user_by( 'id', $user_id );
120
121        if ( ! ( $user instanceof WP_User ) ) {
122            // TODO Log.
123            return null;
124        }
125
126        $user_roles = $user->roles;
127
128        $test_data['wp_user_id']    = $user_id;
129        $test_data['wp_user_roles'] = $user_roles;
130
131        $user_url = admin_url( 'user-edit.php?user_id=' . $user_id );
132
133        $test_html_output = '<p>WordPress <a href="' . $user_url . '">user ' . $user_id . '</a> created with roles: <em>' . implode( ', ', $user_roles ) . '</em></p>';
134
135        return array(
136            'data' => $test_data,
137            'html' => $test_html_output,
138        );
139    }
140
141    /**
142     * The test succeeded if the user had the bounced_email role added.
143     *
144     * @param array{wp_user_id:int, wp_user_roles:string|string[]} $test_data { string: wp_user_id, string[]: wp_user_roles }.
145     *
146     * @return array<string, mixed>
147     */
148    public function verify_test( array $test_data ): ?array {
149
150        $user = get_user_by( 'id', intval( $test_data['wp_user_id'] ) );
151
152        if ( ! ( $user instanceof WP_User ) ) {
153            $this->logger->error( 'Unexpectedly could not find user', array( 'test_data' => $test_data ) );
154            return array();
155        }
156
157        $user_roles = $user->roles;
158
159        $previous_user_roles = (array) $test_data['wp_user_roles'];
160
161        $new_roles = array_diff( $user_roles, $previous_user_roles );
162
163        // TODO: Check for the bounced_email role, not just for "a role was added".
164        $success = ! empty( $new_roles );
165
166        $user_url = admin_url( 'user-edit.php?user_id=' . $user->ID );
167
168        if ( $success ) {
169
170            $html = 'WordPress <a href="' . esc_url( $user_url ) . '">user ' . $user->ID . '</a> found with new roles: <em>' . implode( ', ', $new_roles ) . '</em>.';
171
172        } else {
173
174            $html = 'No new roles added to <a href="' . esc_url( $user_url ) . '">user ' . $user->ID . '</a>.';
175        }
176
177        return array(
178            'success' => $success,
179            'html'    => $html,
180        );
181
182    }
183
184    /**
185     * Delete the user created during the test.
186     *
187     * @param array{wp_user_id?:int} $test_data The data created and saved during setup_test().
188     *
189     * @return bool
190     */
191    public function delete_test_data( array $test_data ): bool {
192
193        if ( isset( $test_data['wp_user_id'] ) ) {
194            $result = wp_delete_user( intval( $test_data['wp_user_id'] ) );
195
196            return $result;
197        }
198        return false;
199    }
200}