44
55namespace Yoast \WP \SEO \AI \Consent \Application ;
66
7+ use Yoast \WP \SEO \AI \Authorization \Application \Token_Manager ;
8+ use Yoast \WP \SEO \AI \HTTP_Request \Application \Request_Handler ;
9+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Bad_Request_Exception ;
10+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Forbidden_Exception ;
11+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Internal_Server_Error_Exception ;
12+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Not_Found_Exception ;
13+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Payment_Required_Exception ;
14+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Remote_Request_Exception ;
15+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Request_Timeout_Exception ;
16+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Service_Unavailable_Exception ;
17+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Too_Many_Requests_Exception ;
18+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \Unauthorized_Exception ;
19+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Exceptions \WP_Request_Exception ;
20+ use Yoast \WP \SEO \AI \HTTP_Request \Domain \Request ;
721use Yoast \WP \SEO \Helpers \User_Helper ;
22+ use Yoast \WP \SEO \Loggers \Logger ;
823
924/**
1025 * Class Consent_Handler
11- * Handles the consent given or revoked by the user.
26+ * Handles the consent given or revoked by the user, both locally (user meta) and remotely (Yoast AI service) .
1227 *
1328 * @makePublic
1429 */
@@ -21,34 +36,112 @@ class Consent_Handler implements Consent_Handler_Interface {
2136 */
2237 private $ user_helper ;
2338
39+ /**
40+ * The token manager instance.
41+ *
42+ * @var Token_Manager
43+ */
44+ private $ token_manager ;
45+
46+ /**
47+ * The request handler instance.
48+ *
49+ * @var Request_Handler
50+ */
51+ private $ request_handler ;
52+
53+ /**
54+ * The logger instance.
55+ *
56+ * @var Logger
57+ */
58+ private $ logger ;
59+
2460 /**
2561 * Class constructor.
2662 *
27- * @param User_Helper $user_helper The user helper.
63+ * @param User_Helper $user_helper The user helper.
64+ * @param Token_Manager $token_manager The token manager, used to obtain a JWT for the consent endpoints.
65+ * @param Request_Handler $request_handler The request handler, used to call the AI service's consent endpoints.
66+ * @param Logger $logger The logger, used to record best-effort failures during revoke.
2867 */
29- public function __construct ( User_Helper $ user_helper ) {
30- $ this ->user_helper = $ user_helper ;
68+ public function __construct (
69+ User_Helper $ user_helper ,
70+ Token_Manager $ token_manager ,
71+ Request_Handler $ request_handler ,
72+ Logger $ logger
73+ ) {
74+ $ this ->user_helper = $ user_helper ;
75+ $ this ->token_manager = $ token_manager ;
76+ $ this ->request_handler = $ request_handler ;
77+ $ this ->logger = $ logger ;
3178 }
3279
80+ // phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- PHPCS doesn't take into account exceptions thrown in called methods.
81+
3382 /**
34- * Handles consent revoked by deleting the consent user metadata from the database.
83+ * Records the user's consent on the Yoast AI service and, on success, in the local user meta.
84+ *
85+ * Transactional: any HTTP-layer exception is propagated and the local meta is left untouched, so
86+ * the local and server state stay in sync.
3587 *
3688 * @param int $user_id The user ID.
3789 *
3890 * @return void
91+ *
92+ * @throws Bad_Request_Exception When the AI service responds with 400.
93+ * @throws Forbidden_Exception When the AI service responds with 403.
94+ * @throws Internal_Server_Error_Exception When the AI service responds with 500.
95+ * @throws Not_Found_Exception When the AI service responds with 404.
96+ * @throws Payment_Required_Exception When the AI service responds with 402.
97+ * @throws Request_Timeout_Exception When the AI service responds with 408.
98+ * @throws Service_Unavailable_Exception When the AI service responds with 503.
99+ * @throws Too_Many_Requests_Exception When the AI service responds with 429.
100+ * @throws Unauthorized_Exception When the AI service responds with 401.
101+ * @throws WP_Request_Exception When the underlying WordPress HTTP call fails.
39102 */
40- public function revoke_consent ( int $ user_id ) {
41- $ this ->user_helper ->delete_meta ( $ user_id , '_yoast_wpseo_ai_consent ' );
103+ public function grant_consent ( int $ user_id ) {
104+ $ user = \get_user_by ( 'id ' , $ user_id );
105+ $ jwt = $ this ->token_manager ->get_or_request_access_token ( $ user );
106+
107+ $ this ->request_handler ->handle (
108+ new Request ( '/user/consent ' , [], [ 'Authorization ' => "Bearer $ jwt " ], Request::METHOD_POST ),
109+ );
110+
111+ $ this ->user_helper ->update_meta ( $ user_id , '_yoast_wpseo_ai_consent ' , true );
42112 }
43113
44114 /**
45- * Handles consent granted by adding the consent user metadata to the database.
115+ * Revokes the user's consent on the Yoast AI service and clears the local user meta.
116+ *
117+ * Security-first: the local meta is always cleared, even if the remote DELETE fails. HTTP-layer
118+ * failures are logged as warnings and swallowed; programmer errors (non-`Remote_Request_Exception`
119+ * / non-`WP_Request_Exception`) are not caught and will propagate.
46120 *
47121 * @param int $user_id The user ID.
48122 *
49123 * @return void
50124 */
51- public function grant_consent ( int $ user_id ) {
52- $ this ->user_helper ->update_meta ( $ user_id , '_yoast_wpseo_ai_consent ' , true );
125+ public function revoke_consent ( int $ user_id ) {
126+ try {
127+ $ user = \get_user_by ( 'id ' , $ user_id );
128+ $ jwt = $ this ->token_manager ->get_or_request_access_token ( $ user );
129+
130+ $ this ->request_handler ->handle (
131+ new Request ( '/user/consent ' , [], [ 'Authorization ' => "Bearer $ jwt " ], Request::METHOD_DELETE ),
132+ );
133+ } catch ( Remote_Request_Exception | WP_Request_Exception $ e ) {
134+ $ this ->logger ->warning (
135+ 'Failed to revoke consent on the Yoast AI service; clearing local consent anyway. ' ,
136+ [
137+ 'user_id ' => $ user_id ,
138+ 'exception ' => $ e ->getMessage (),
139+ ],
140+ );
141+ }
142+
143+ $ this ->user_helper ->delete_meta ( $ user_id , '_yoast_wpseo_ai_consent ' );
53144 }
145+
146+ // phpcs:enable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
54147}
0 commit comments