Skip to content

Commit d0de53e

Browse files
committed
Store user consent in Yoast AI
1 parent 50e815a commit d0de53e

1 file changed

Lines changed: 103 additions & 10 deletions

File tree

src/ai/consent/application/consent-handler.php

Lines changed: 103 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,26 @@
44

55
namespace 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;
721
use 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

Comments
 (0)