Passed
Branch main (d68b9c)
by smiley
09:54
created

MusicBrainz   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 90
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 9
eloc 46
c 1
b 0
f 0
dl 0
loc 90
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A refreshAccessToken() 0 37 4
A request() 0 26 5
1
<?php
2
/**
3
 * Class MusicBrainz
4
 *
5
 * @link https://musicbrainz.org/doc/Development
6
 * @link https://musicbrainz.org/doc/Development/OAuth2
7
 *
8
 * @filesource   MusicBrainz.php
9
 * @created      31.07.2018
10
 * @package      chillerlan\OAuth\Providers
11
 * @author       Smiley <[email protected]>
12
 * @copyright    2017 Smiley
13
 * @license      MIT
14
 */
15
16
namespace chillerlan\OAuth\Providers\MusicBrainz;
17
18
use chillerlan\OAuth\Core\{AccessToken, CSRFToken, OAuth2Provider, ProviderException, TokenRefresh};
19
use Psr\Http\Message\ResponseInterface;
20
21
use function array_merge, date, explode, http_build_query, in_array, sprintf, strtoupper;
22
23
use const PHP_QUERY_RFC1738;
24
25
/**
26
 * @method \Psr\Http\Message\ResponseInterface area(array $params = ['inc', 'query', 'limit', 'offset', 'collection'])
27
 * @method \Psr\Http\Message\ResponseInterface areaId(string $id, array $params = ['inc'])
28
 * @method \Psr\Http\Message\ResponseInterface artist(array $params = ['inc', 'query', 'limit', 'offset', 'area', 'collection', 'recording', 'release', 'release-group', 'work'])
29
 * @method \Psr\Http\Message\ResponseInterface artistId(string $id, array $params = ['inc'])
30
 * @method \Psr\Http\Message\ResponseInterface collection(array $params = ['query', 'limit', 'offset', 'area', 'artist', 'editor', 'event', 'label', 'place', 'recording', 'release', 'release-group', 'work'])
31
 * @method \Psr\Http\Message\ResponseInterface collectionAdd(string $collectionID, string $releaseIDs, array $params = ['client'], array $body = [''])
32
 * @method \Psr\Http\Message\ResponseInterface collectionId(string $id)
33
 * @method \Psr\Http\Message\ResponseInterface collectionRemove(string $collectionID, string $releaseIDs, array $params = ['client'], array $body = [''])
34
 * @method \Psr\Http\Message\ResponseInterface discid(array $params = ['inc'])
35
 * @method \Psr\Http\Message\ResponseInterface event(array $params = ['inc', 'query', 'limit', 'offset', 'area', 'artist', 'collection', 'place'])
36
 * @method \Psr\Http\Message\ResponseInterface eventId(string $id, array $params = ['inc'])
37
 * @method \Psr\Http\Message\ResponseInterface instrument(array $params = ['inc', 'query', 'limit', 'offset'])
38
 * @method \Psr\Http\Message\ResponseInterface instrumentId(string $id, array $params = ['inc'])
39
 * @method \Psr\Http\Message\ResponseInterface isrc(array $params = ['inc'])
40
 * @method \Psr\Http\Message\ResponseInterface iswc(array $params = ['inc'])
41
 * @method \Psr\Http\Message\ResponseInterface label(array $params = ['inc', 'query', 'limit', 'offset', 'area', 'collection', 'release'])
42
 * @method \Psr\Http\Message\ResponseInterface labelId(string $id, array $params = ['inc'])
43
 * @method \Psr\Http\Message\ResponseInterface place(array $params = ['inc', 'query', 'limit', 'offset', 'area', 'collection'])
44
 * @method \Psr\Http\Message\ResponseInterface placeId(string $id, array $params = ['inc'])
45
 * @method \Psr\Http\Message\ResponseInterface rating(array $params = ['query', 'limit', 'offset'])
46
 * @method \Psr\Http\Message\ResponseInterface ratingId(string $id)
47
 * @method \Psr\Http\Message\ResponseInterface ratingSubmit(array $params = ['client'], array $body = [''])
48
 * @method \Psr\Http\Message\ResponseInterface recording(array $params = ['inc', 'query', 'limit', 'offset', 'artist', 'collection', 'release'])
49
 * @method \Psr\Http\Message\ResponseInterface recordingId(string $id, array $params = ['inc'])
50
 * @method \Psr\Http\Message\ResponseInterface release(array $params = ['inc', 'query', 'limit', 'offset', 'type', 'status', 'area', 'artist', 'collection', 'label', 'track', 'track_artist', 'recording', 'release-group'])
51
 * @method \Psr\Http\Message\ResponseInterface releaseGroup(array $params = ['inc', 'query', 'limit', 'offset', 'type', 'artist', 'collection', 'release'])
52
 * @method \Psr\Http\Message\ResponseInterface releaseGroupId(string $id, array $params = ['inc'])
53
 * @method \Psr\Http\Message\ResponseInterface releaseId(string $id, array $params = ['inc'])
54
 * @method \Psr\Http\Message\ResponseInterface series(array $params = ['inc', 'query', 'limit', 'offset', 'collection'])
55
 * @method \Psr\Http\Message\ResponseInterface seriesId(string $id, array $params = ['inc'])
56
 * @method \Psr\Http\Message\ResponseInterface tag(array $params = ['query', 'limit', 'offset'])
57
 * @method \Psr\Http\Message\ResponseInterface tagId(string $id)
58
 * @method \Psr\Http\Message\ResponseInterface tagVote(array $params = ['client'], array $body = [''])
59
 * @method \Psr\Http\Message\ResponseInterface url(array $params = ['inc', 'query', 'limit', 'offset', 'resource'])
60
 * @method \Psr\Http\Message\ResponseInterface urlId(string $id, array $params = ['inc'])
61
 * @method \Psr\Http\Message\ResponseInterface user(array $params = ['name'])
62
 * @method \Psr\Http\Message\ResponseInterface work(array $params = ['inc', 'query', 'limit', 'offset', 'artist', 'collection'])
63
 * @method \Psr\Http\Message\ResponseInterface workId(string $id, array $params = ['inc'])
64
 */
65
class MusicBrainz extends OAuth2Provider implements CSRFToken, TokenRefresh{
66
67
	const SCOPE_PROFILE        = 'profile';
68
	const SCOPE_EMAIL          = 'email';
69
	const SCOPE_TAG            = 'tag';
70
	const SCOPE_RATING         = 'rating';
71
	const SCOPE_COLLECTION     = 'collection';
72
	const SCOPE_SUBMIT_ISRC    = 'submit_isrc';
73
	const SCOPE_SUBMIT_BARCODE = 'submit_barcode';
74
75
	protected string $authURL         = 'https://musicbrainz.org/oauth2/authorize';
76
	protected string $accessTokenURL  = 'https://musicbrainz.org/oauth2/token';
77
	protected ?string $apiURL         = 'https://musicbrainz.org/ws/2';
78
	protected ?string $userRevokeURL  = 'https://musicbrainz.org/account/applications';
79
	protected ?string $endpointMap    = MusicBrainzEndpoints::class;
80
	protected ?string $apiDocs        = 'https://musicbrainz.org/doc/Development';
81
	protected ?string $applicationURL = 'https://musicbrainz.org/account/applications';
82
83
	/**
84
	 * @inheritdoc
85
	 * @throws \chillerlan\OAuth\Core\ProviderException
86
	 */
87
	public function refreshAccessToken(AccessToken $token = null):AccessToken{
88
89
		if($token === null){
90
			$token = $this->storage->getAccessToken($this->serviceName);
91
		}
92
93
		$refreshToken = $token->refreshToken;
94
95
		if(empty($refreshToken)){
96
			throw new ProviderException(
97
				sprintf('no refresh token available, token expired [%s]', date('Y-m-d h:i:s A', $token->expires))
98
			);
99
		}
100
101
		$body = [
102
			'client_id'     => $this->options->key,
103
			'client_secret' => $this->options->secret,
104
			'grant_type'    => 'refresh_token',
105
			'refresh_token' => $refreshToken,
106
		];
107
108
		$request = $this->requestFactory
109
			->createRequest('POST', $this->refreshTokenURL ?? $this->accessTokenURL) // refreshTokenURL is used in tests
110
			->withHeader('Content-Type', 'application/x-www-form-urlencoded')
111
			->withHeader('Accept-Encoding', 'identity')
112
			->withBody($this->streamFactory->createStream(http_build_query($body, '', '&', PHP_QUERY_RFC1738)))
113
		;
114
115
		$newToken = $this->parseTokenResponse($this->http->sendRequest($request));
116
117
		if(empty($newToken->refreshToken)){
118
			$newToken->refreshToken = $refreshToken;
119
		}
120
121
		$this->storage->storeAccessToken($this->serviceName, $newToken);
122
123
		return $newToken;
124
	}
125
126
	/**
127
	 * @inheritDoc
128
	 */
129
	public function request(
130
		string $path,
131
		array $params = null,
132
		string $method = null,
133
		$body = null,
134
		array $headers = null
135
	):ResponseInterface{
136
		$params = $params ?? [];
137
		$method = strtoupper($method ?? '');
138
		$token  = $this->storage->getAccessToken($this->serviceName);
139
140
		if($token->isExpired()){
141
			$token = $this->refreshAccessToken($token);
142
		}
143
144
		if(!isset($params['fmt'])){
145
			$params['fmt'] = 'json';
146
		}
147
148
		if(in_array($method, ['POST', 'PUT', 'DELETE']) && !isset($params['client'])){
149
			$params['client'] = $this->options->user_agent; // @codeCoverageIgnore
150
		}
151
152
		$headers = array_merge($this->apiHeaders, $headers ?? [], ['Authorization' => 'Bearer '.$token->accessToken]);
153
154
		return parent::request(explode('?', $path)[0], $params, $method, $body, $headers);
155
	}
156
157
}
158