friendship ended with social-app. php is my new best friend
1<?php 2/** 3 * Class MailChimp 4 * 5 * @created 16.08.2018 6 * @author smiley <smiley@chillerlan.net> 7 * @copyright 2018 smiley 8 * @license MIT 9 */ 10declare(strict_types=1); 11 12namespace chillerlan\OAuth\Providers; 13 14use chillerlan\HTTP\Utils\MessageUtil; 15use chillerlan\OAuth\Core\{AccessToken, AuthenticatedUser, CSRFToken, OAuth2Provider, UserInfo}; 16use chillerlan\OAuth\OAuthException; 17use Psr\Http\Message\{ResponseInterface, StreamInterface}; 18use function array_merge, sprintf; 19 20/** 21 * MailChimp OAuth2 22 * 23 * @link https://mailchimp.com/developer/ 24 * @link https://mailchimp.com/developer/marketing/guides/access-user-data-oauth-2/ 25 */ 26class MailChimp extends OAuth2Provider implements CSRFToken, UserInfo{ 27 28 public const IDENTIFIER = 'MAILCHIMP'; 29 30 protected const API_BASE = 'https://%s.api.mailchimp.com'; 31 protected const METADATA_ENDPOINT = 'https://login.mailchimp.com/oauth2/metadata'; 32 33 protected string $authorizationURL = 'https://login.mailchimp.com/oauth2/authorize'; 34 protected string $accessTokenURL = 'https://login.mailchimp.com/oauth2/token'; 35 protected string|null $apiDocs = 'https://mailchimp.com/developer/'; 36 protected string|null $applicationURL = 'https://admin.mailchimp.com/account/oauth2/'; 37 // set to empty so that we don't run into "uninitialized" errors in mock tests, as the datacenter is in the token 38 protected string $apiURL = ''; 39 40 public function getAccessToken(string $code, string|null $state = null):AccessToken{ 41 $this->checkState($state); 42 43 $body = $this->getAccessTokenRequestBodyParams($code); 44 $response = $this->sendAccessTokenRequest($this->accessTokenURL, $body); 45 $token = $this->parseTokenResponse($response); 46 47 // MailChimp needs another call to the auth metadata endpoint 48 // to receive the datacenter prefix/API URL, which will then 49 // be stored in AccessToken::$extraParams 50 51 return $this->getTokenMetadata($token); 52 } 53 54 /** 55 * @throws \chillerlan\OAuth\OAuthException 56 */ 57 public function getTokenMetadata(AccessToken|null $token = null):AccessToken{ 58 $token ??= $this->storage->getAccessToken($this->name); 59 60 $request = $this->requestFactory 61 ->createRequest('GET', $this::METADATA_ENDPOINT) 62 ->withHeader('Authorization', 'OAuth '.$token->accessToken) 63 ; 64 65 $response = $this->http->sendRequest($request); 66 67 if($response->getStatusCode() !== 200){ 68 throw new OAuthException('metadata response error'); // @codeCoverageIgnore 69 } 70 71 $token->extraParams = array_merge($token->extraParams, MessageUtil::decodeJSON($response, true)); 72 73 $this->storage->storeAccessToken($token, $this->name); 74 75 return $token; 76 } 77 78 public function request( 79 string $path, 80 array|null $params = null, 81 string|null $method = null, 82 StreamInterface|array|string|null $body = null, 83 array|null $headers = null, 84 string|null $protocolVersion = null, 85 ):ResponseInterface{ 86 $token = $this->storage->getAccessToken($this->name); 87 // get the API URL from the token metadata 88 $this->apiURL = sprintf($this::API_BASE, $token->extraParams['dc']); 89 90 return parent::request($path, $params, $method, $body, $headers, $protocolVersion); 91 } 92 93 protected function sendMeRequest(string $endpoint, array|null $params = null):ResponseInterface{ 94 return $this->request(path: $endpoint, params: $params); 95 } 96 97 /** 98 * @link https://mailchimp.com/developer/marketing/api/root/list-api-root-resources/ 99 * 100 * @inheritDoc 101 * @codeCoverageIgnore 102 */ 103 public function me():AuthenticatedUser{ 104 $json = $this->getMeResponseData('/3.0/'); // trailing slash! 105 106 $userdata = [ 107 'data' => $json, 108 'avatar' => $json['avatar_url'], 109 'displayName' => $json['username'], 110 'handle' => $json['account_name'], 111 'email' => $json['email'], 112 'id' => $json['account_id'], 113 ]; 114 115 return new AuthenticatedUser($userdata); 116 } 117 118}