Added currently existent V1 routes.
This commit is contained in:
parent
58cbf592fe
commit
094fb8e5b4
24 changed files with 653 additions and 47 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.1.1
|
||||
0.2.0
|
||||
|
|
|
@ -6,19 +6,21 @@
|
|||
namespace Flashii;
|
||||
|
||||
use Flashii\Credentials\Credentials;
|
||||
use Flashii\Http\{HttpClient,HttpRequest,HttpResponse};
|
||||
use Flashii\Http\{HttpClient,HttpRequest,HttpResponse,RequestSpeedrun};
|
||||
|
||||
/**
|
||||
* Provides a proxy HttpClient that ensures the HTTP Authorization header is set on requests.
|
||||
*/
|
||||
class AuthorizedHttpClient implements HttpClient {
|
||||
use RequestSpeedrun;
|
||||
|
||||
/**
|
||||
* @param HttpClient $httpClient Underlying HttpClient implementation.
|
||||
* @param Credentials $credentials Credentials to use for the Authorization header.
|
||||
*/
|
||||
public function __construct(
|
||||
private HttpClient $httpClient,
|
||||
private Credentials $credentials
|
||||
private readonly HttpClient $httpClient,
|
||||
private readonly Credentials $credentials
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,14 +9,14 @@ namespace Flashii\Credentials;
|
|||
* Implements basic HTTP credentials for OAuth2 apps.
|
||||
*/
|
||||
class BasicCredentials implements Credentials {
|
||||
private string $authz;
|
||||
private readonly string $authz;
|
||||
|
||||
/**
|
||||
* @param string $userName User name/Client ID.
|
||||
* @param string $password Password/Client secret.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $userName,
|
||||
private readonly string $userName,
|
||||
#[\SensitiveParameter]
|
||||
string $password = ''
|
||||
) {
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace Flashii\Credentials;
|
|||
* Implements bearer HTTP credentials for OAuth2 access tokens.
|
||||
*/
|
||||
class BearerCredentials implements Credentials {
|
||||
private string $authz;
|
||||
private readonly string $authz;
|
||||
|
||||
/**
|
||||
* @param string $accessToken Bearer access token.
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Flashii\Credentials;
|
|||
* Do not use this unless you're flashwave!!!!!!! bad!!!!!!!!
|
||||
*/
|
||||
class MisuzuCredentials implements Credentials {
|
||||
private string $authz;
|
||||
private readonly string $authz;
|
||||
|
||||
/**
|
||||
* @param string $sessionToken Misuzu session token.
|
||||
|
|
|
@ -11,6 +11,7 @@ use Flashii\Http\HttpClient;
|
|||
use Flashii\Http\Curl\CurlHttpClient;
|
||||
use Flashii\Http\Stream\StreamHttpClient;
|
||||
use Flashii\OAuth2\OAuth2Client;
|
||||
use Flashii\V1\V1Client;
|
||||
|
||||
/**
|
||||
* Flashii API client.
|
||||
|
@ -37,12 +38,13 @@ class FlashiiClient {
|
|||
*/
|
||||
public const LIB_PATH_VERSION = self::LIB_PATH_ROOT . DIRECTORY_SEPARATOR . 'VERSION';
|
||||
|
||||
private AuthorizedHttpClient $httpClient;
|
||||
private Credentials $credentials;
|
||||
private FlashiiUrls $urls;
|
||||
private readonly AuthorizedHttpClient $httpClient;
|
||||
private readonly Credentials $credentials;
|
||||
private readonly FlashiiUrls $urls;
|
||||
|
||||
// Use newLazyGhost to initialise these once PHP 8.4 can be targeted proper
|
||||
private ?OAuth2Client $oauth2 = null;
|
||||
private ?V1Client $v1 = null;
|
||||
|
||||
/**
|
||||
* @param string $userAgentOrHttpClient User agent string for your application or a HttpClient implementation, providing a string will autodetect whether to use cURL or PHP streams.
|
||||
|
@ -88,6 +90,20 @@ class FlashiiClient {
|
|||
return $this->oauth2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the APIv1 client portion.
|
||||
*
|
||||
* @return V1Client
|
||||
*/
|
||||
public function v1(): V1Client {
|
||||
$this->v1 ??= new V1Client(
|
||||
$this->httpClient,
|
||||
$this->urls
|
||||
);
|
||||
|
||||
return $this->v1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fork this API client with different credentials.
|
||||
*
|
||||
|
|
|
@ -28,8 +28,8 @@ final class FlashiiUrls {
|
|||
* @param string $idUrl ID service base URL, without trailing /.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $apiUrl,
|
||||
private string $idUrl
|
||||
private readonly string $apiUrl,
|
||||
private readonly string $idUrl
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,20 +8,23 @@ namespace Flashii\Http\Curl;
|
|||
use CurlHandle;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Flashii\Http\{HttpClient,HttpRequest,HttpResponse};
|
||||
use Flashii\Http\{HttpClient,HttpRequest,HttpResponse,RequestSpeedrun};
|
||||
|
||||
/**
|
||||
* cURL extension backed HTTP client implementation.
|
||||
*/
|
||||
class CurlHttpClient implements HttpClient {
|
||||
private CurlHandle $handle;
|
||||
use RequestSpeedrun;
|
||||
|
||||
private readonly string $userAgent;
|
||||
private readonly CurlHandle $handle;
|
||||
|
||||
/**
|
||||
* @param string $userAgent User-Agent string.
|
||||
* @throws RuntimeException If cURL initialisation failed.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $userAgent
|
||||
string $userAgent
|
||||
) {
|
||||
$handle = curl_init();
|
||||
if($handle === false)
|
||||
|
|
|
@ -19,10 +19,10 @@ class CurlHttpResponse implements HttpResponse {
|
|||
* @param string $body HTTP body.
|
||||
*/
|
||||
public function __construct(
|
||||
private int $statusCode,
|
||||
private string $statusText,
|
||||
private array $headers,
|
||||
private string $body
|
||||
private readonly int $statusCode,
|
||||
private readonly string $statusText,
|
||||
private readonly array $headers,
|
||||
private readonly string $body
|
||||
) {}
|
||||
|
||||
public function getStatusCode(): int {
|
||||
|
|
|
@ -27,8 +27,22 @@ interface HttpClient {
|
|||
*
|
||||
* @param HttpRequest $request Request to send.
|
||||
* @throws InvalidArgumentException If $request is not understood by the HttpClient implementation.
|
||||
* @throws RuntimeException If the HTTP request failed in an unexpected way.
|
||||
* @throws RuntimeException If the request failed in an unexpected way.
|
||||
* @return HttpResponse
|
||||
*/
|
||||
function sendRequest(HttpRequest $request): HttpResponse;
|
||||
|
||||
/**
|
||||
* Combines createRequest and sendRequest into one method call.
|
||||
*
|
||||
* Less noise for when we don't need to touch HttpRequest :)
|
||||
*
|
||||
* @param string $method Desired request method.
|
||||
* @param string $url Target URL.
|
||||
* @throws InvalidArgumentException If $request is not understood by the HttpClient implementation.
|
||||
* @throws RuntimeException If the request could not be initialised.
|
||||
* @throws RuntimeException If the request failed in an unexpected way.
|
||||
* @return HttpResponse
|
||||
*/
|
||||
function request(string $method, string $url): HttpResponse;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
namespace Flashii\Http;
|
||||
|
||||
use RuntimeException;
|
||||
/**
|
||||
* Common implementation for the getJsonBody method of HttpResponse.
|
||||
*/
|
||||
|
|
30
src/Http/RequestSpeedrun.php
Normal file
30
src/Http/RequestSpeedrun.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php declare(strict_types=1);
|
||||
// RequestSpeedrun.php
|
||||
// Created: 2024-11-16
|
||||
// Updated: 2024-11-16
|
||||
|
||||
namespace Flashii\Http;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Common implementation for the request method of HttpClient.
|
||||
*/
|
||||
trait RequestSpeedrun {
|
||||
/**
|
||||
* Combines createRequest and sendRequest into one method call.
|
||||
*
|
||||
* Less noise for when we don't need to touch HttpRequest :)
|
||||
*
|
||||
* @param string $method Desired request method.
|
||||
* @param string $url Target URL.
|
||||
* @throws InvalidArgumentException If $request is not understood by the HttpClient implementation.
|
||||
* @throws RuntimeException If the request could not be initialised.
|
||||
* @throws RuntimeException If the request failed in an unexpected way.
|
||||
* @return HttpResponse
|
||||
*/
|
||||
public function request(string $method, string $url): HttpResponse {
|
||||
return $this->sendRequest($this->createRequest($method, $url));
|
||||
}
|
||||
}
|
|
@ -7,17 +7,19 @@ namespace Flashii\Http\Stream;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Flashii\Http\{HttpClient,HttpRequest,HttpResponse};
|
||||
use Flashii\Http\{HttpClient,HttpRequest,HttpResponse,RequestSpeedrun};
|
||||
|
||||
/**
|
||||
* PHP stream backed HTTP client implementation.
|
||||
*/
|
||||
class StreamHttpClient implements HttpClient {
|
||||
use RequestSpeedrun;
|
||||
|
||||
/**
|
||||
* @param string $userAgent User-Agent string.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $userAgent
|
||||
private readonly string $userAgent
|
||||
) {}
|
||||
|
||||
public function createRequest(string $method, string $url): HttpRequest {
|
||||
|
|
|
@ -19,10 +19,10 @@ class StreamHttpResponse implements HttpResponse {
|
|||
* @param string $body HTTP body.
|
||||
*/
|
||||
public function __construct(
|
||||
private int $statusCode,
|
||||
private string $statusText,
|
||||
private array $headers,
|
||||
private string $body
|
||||
private readonly int $statusCode,
|
||||
private readonly string $statusText,
|
||||
private readonly array $headers,
|
||||
private readonly string $body
|
||||
) {}
|
||||
|
||||
public function getStatusCode(): int {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
namespace Flashii\Http;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Common implementation for the SuccessStatusCode methods of HttpResponse.
|
||||
*/
|
||||
|
|
|
@ -18,12 +18,12 @@ final class OAuth2AuthorizationRequest {
|
|||
* @param int $interval Interval of seconds to check at.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $deviceCode,
|
||||
private string $userCode,
|
||||
private string $verificationUri,
|
||||
private string $verificationUriComplete,
|
||||
private int $expiresIn,
|
||||
private int $interval
|
||||
private readonly string $deviceCode,
|
||||
private readonly string $userCode,
|
||||
private readonly string $verificationUri,
|
||||
private readonly string $verificationUriComplete,
|
||||
private readonly int $expiresIn,
|
||||
private readonly int $interval
|
||||
) {}
|
||||
|
||||
public function getDeviceCode(): string {
|
||||
|
|
|
@ -21,10 +21,10 @@ class OAuth2Client {
|
|||
* @param FlashiiUrls $urls API URLs.
|
||||
*/
|
||||
public function __construct(
|
||||
private FlashiiClient $flashiiClient,
|
||||
private AuthorizedHttpClient $httpClient,
|
||||
private Credentials $credentials,
|
||||
private FlashiiUrls $urls
|
||||
private readonly FlashiiClient $flashiiClient,
|
||||
private readonly AuthorizedHttpClient $httpClient,
|
||||
private readonly Credentials $credentials,
|
||||
private readonly FlashiiUrls $urls
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,9 +15,9 @@ final class OAuth2Error {
|
|||
* @param string $uri Error URI.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $error,
|
||||
private string $description,
|
||||
private string $uri
|
||||
private readonly string $error,
|
||||
private readonly string $description,
|
||||
private readonly string $uri
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
namespace Flashii\OAuth2;
|
||||
|
||||
use Flashii\Credentials\BearerCredentials;
|
||||
/**
|
||||
* OAuth2 token response.
|
||||
*/
|
||||
|
@ -18,11 +17,11 @@ final class OAuth2Token {
|
|||
* @param string $refreshToken Refresh token.
|
||||
*/
|
||||
public function __construct(
|
||||
private string $accessToken,
|
||||
private string $tokenType,
|
||||
private int $expiresIn,
|
||||
private string $scope,
|
||||
private string $refreshToken
|
||||
private readonly string $accessToken,
|
||||
private readonly string $tokenType,
|
||||
private readonly int $expiresIn,
|
||||
private readonly string $scope,
|
||||
private readonly string $refreshToken
|
||||
) {}
|
||||
|
||||
public function getAccessToken(): string {
|
||||
|
|
84
src/V1/Emotes/V1Emote.php
Normal file
84
src/V1/Emotes/V1Emote.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php declare(strict_types=1);
|
||||
// V1Emote.php
|
||||
// Created: 2024-11-16
|
||||
// Updated: 2024-11-16
|
||||
|
||||
namespace Flashii\V1\Emotes;
|
||||
|
||||
/**
|
||||
* Represents an APIv1 emote.
|
||||
*/
|
||||
final class V1Emote {
|
||||
/**
|
||||
* @param string $url URI to the emote image.
|
||||
* @param string[] $strings Emote strings.
|
||||
* @param string $id Internal system ID of the emote.
|
||||
* @param int $order Internal ordering of the emote.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly string $url,
|
||||
private readonly array $strings,
|
||||
private readonly string $id,
|
||||
private readonly int $order
|
||||
) {}
|
||||
|
||||
/**
|
||||
* URI of the emote image.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl(): string {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strings that the emote should replace, surrounding colon characters omitted.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getStrings(): array {
|
||||
return $this->strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal unique ID of the emote. May be blank on some requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ordering of the emote. May be blank on some requests.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an object into this proper object.
|
||||
*
|
||||
* @param object $info
|
||||
* @return V1Emote
|
||||
*/
|
||||
public static function decode(object $info): self {
|
||||
return new static(
|
||||
isset($info->url) && is_string($info->url) ? $info->url : '',
|
||||
isset($info->strings) && is_array($info->strings) ? $info->strings : [], // @phpstan-ignore-line: complains because the constructor expects array<string> but its just getting array, not sure how to solve this
|
||||
isset($info->id) && is_string($info->id) ? $info->id : '',
|
||||
isset($info->order) && is_int($info->order) ? $info->order : 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a blank emote instance.
|
||||
*
|
||||
* @return V1Emote
|
||||
*/
|
||||
public static function empty(): self {
|
||||
return new static('', [], '', 0);
|
||||
}
|
||||
}
|
53
src/V1/Emotes/V1EmotesClient.php
Normal file
53
src/V1/Emotes/V1EmotesClient.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php declare(strict_types=1);
|
||||
// V1EmotesClient.php
|
||||
// Created: 2024-11-16
|
||||
// Updated: 2024-11-16
|
||||
|
||||
namespace Flashii\V1\Emotes;
|
||||
|
||||
use Flashii\FlashiiUrls;
|
||||
use Flashii\Http\HttpClient;
|
||||
|
||||
/**
|
||||
* Implements the APIv1 emotes portion.
|
||||
*/
|
||||
class V1EmotesClient {
|
||||
/**
|
||||
* @param HttpClient $httpClient HTTP client.
|
||||
* @param FlashiiUrls $urls API URLs.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly HttpClient $httpClient,
|
||||
private readonly FlashiiUrls $urls
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieves a list of all emotes.
|
||||
*
|
||||
* @param bool $includeOrder Whether to include the ordering values.
|
||||
* @param bool $includeIds Whether to include internal Ids.
|
||||
* @return V1Emote[]
|
||||
*/
|
||||
public function all(
|
||||
bool $includeOrder = false,
|
||||
bool $includeIds = false
|
||||
): array {
|
||||
$args = [];
|
||||
if($includeIds)
|
||||
$args['include_id'] = '1';
|
||||
if($includeOrder)
|
||||
$args['include_order'] = '1';
|
||||
|
||||
$response = $this->httpClient->request('GET', $this->urls->getApiUrl('/v1/emotes', $args));
|
||||
$response->ensureSuccessStatusCode();
|
||||
|
||||
$emotes = $response->getJsonBody();
|
||||
if(!is_array($emotes))
|
||||
return [];
|
||||
|
||||
return array_map(
|
||||
fn(mixed $item) => (is_object($item) ? V1Emote::decode($item) : V1Emote::empty()),
|
||||
$emotes
|
||||
);
|
||||
}
|
||||
}
|
277
src/V1/Users/V1User.php
Normal file
277
src/V1/Users/V1User.php
Normal file
|
@ -0,0 +1,277 @@
|
|||
<?php declare(strict_types=1);
|
||||
// V1User.php
|
||||
// Created: 2024-11-16
|
||||
// Updated: 2024-11-16
|
||||
|
||||
namespace Flashii\V1\Users;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* Represents an APIv1 user.
|
||||
*/
|
||||
final class V1User {
|
||||
/** @var ?V1UserAvatar[] */
|
||||
private ?array $avatarsSorted = null;
|
||||
|
||||
/**
|
||||
* @param string $id User ID.
|
||||
* @param string $name User name.
|
||||
* @param ?int $colourRaw Raw 24-bit RGB value, null for inherit.
|
||||
* @param string $colourCss CSS colour.
|
||||
* @param int $rank User rank.
|
||||
* @param string $countryCode ISO 3166-1 alpha-2 (adjacent) country code.
|
||||
* @param V1UserAvatar[] $avatarUrls Avatar URIs.
|
||||
* @param string $profileUrl Profile URI.
|
||||
* @param DateTimeInterface $createdAt User registration date.
|
||||
* @param ?DateTimeInterface $lastActiveAt Last user activity, null for none or hidden.
|
||||
* @param string[] $roles User role strings.
|
||||
* @param string $title User title.
|
||||
* @param bool $super Super user status.
|
||||
* @param bool $deleted Deleted status.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly string $id,
|
||||
private readonly string $name,
|
||||
private readonly ?int $colourRaw,
|
||||
private readonly string $colourCss,
|
||||
private readonly int $rank,
|
||||
private readonly string $countryCode,
|
||||
private readonly array $avatarUrls,
|
||||
private readonly string $profileUrl,
|
||||
private readonly DateTimeInterface $createdAt,
|
||||
private readonly ?DateTimeInterface $lastActiveAt,
|
||||
private readonly array $roles,
|
||||
private readonly string $title,
|
||||
private readonly bool $super,
|
||||
private readonly bool $deleted
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Gets user ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a raw 24-bit RGB colour is present.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasColourRaw(): bool {
|
||||
return $this->colourRaw !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets raw 24-bit RGB colour value.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getColourRaw(): int {
|
||||
return $this->colourRaw ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets CSS colour.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getColourCss(): string {
|
||||
return $this->colourCss;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user rank.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRank(): int {
|
||||
return $this->rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user ISO 3166-1 alpha-2 (adjacent) country code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCountryCode(): string {
|
||||
return $this->countryCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all avatar URIs.
|
||||
*
|
||||
* @return V1UserAvatar[]
|
||||
*/
|
||||
public function getAvatarUrls(): array {
|
||||
return $this->avatarUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets sorted avatar list URIs without the original URI.
|
||||
*
|
||||
* @return V1UserAvatar[]
|
||||
*/
|
||||
private function getAvatarSorted(): array {
|
||||
if($this->avatarsSorted === null) {
|
||||
$avatars = [];
|
||||
foreach($this->avatarUrls as $avatarUrl)
|
||||
if(!$avatarUrl->isOriginalImage())
|
||||
$avatars[] = $avatarUrl;
|
||||
|
||||
usort($avatars, fn($a, $b) => $a->getResolution() - $b->getResolution());
|
||||
$this->avatarsSorted = $avatars;
|
||||
}
|
||||
|
||||
return $this->avatarsSorted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selected the most appropriate avatar resolution URI.
|
||||
*
|
||||
* @param int $res Target resolution
|
||||
* @return string Avatar URI, empty if none found.
|
||||
*/
|
||||
public function selectAvatarUrl(int $res): string {
|
||||
$selected = null;
|
||||
$avatars = $this->getAvatarSorted();
|
||||
foreach($avatars as $avatar)
|
||||
if($selected === null || abs($res - $selected->getResolution()) >= abs($avatar->getResolution() - $res))
|
||||
$selected = $avatar;
|
||||
|
||||
return $selected?->getUrl() ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URI of the original avatar image, empty if none found.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOriginalAvatarUrl(): string {
|
||||
foreach($this->avatarUrls as $avatarUrl)
|
||||
if($avatarUrl->isOriginalImage())
|
||||
return $avatarUrl->getUrl();
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user profile URI.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getProfileUrl(): string {
|
||||
return $this->profileUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user registration date/time.
|
||||
*
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getCreatedAt(): DateTimeInterface {
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user has a last active date.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasLastActiveAt(): bool {
|
||||
return $this->lastActiveAt !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user last active date.
|
||||
*
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getLastActiveAt(): DateTimeInterface {
|
||||
return $this->lastActiveAt ?? new DateTimeImmutable('@0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user role strings.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getRoles(): array {
|
||||
return $this->roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user has a given role string.
|
||||
*
|
||||
* @param string $role Case-insensitive role string.
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRole(string $role): bool {
|
||||
return in_array(strtolower($role), $this->roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user title.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(): string {
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this is a super user.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuper(): bool {
|
||||
return $this->super;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this user is deleted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDeleted(): bool {
|
||||
return $this->deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an object into this proper object.
|
||||
*
|
||||
* @param object $info
|
||||
* @return V1User
|
||||
*/
|
||||
public static function decode(object $info): self {
|
||||
return new static(
|
||||
isset($info->id) && is_string($info->id) ? $info->id : '',
|
||||
isset($info->name) && is_string($info->name) ? $info->name : '',
|
||||
isset($info->colour_raw) && is_int($info->colour_raw) ? $info->colour_raw : null,
|
||||
isset($info->colour_css) && is_string($info->colour_css) ? $info->colour_css : '',
|
||||
isset($info->rank) && is_int($info->rank) ? $info->rank : 0,
|
||||
isset($info->country_code) && is_string($info->country_code) ? $info->country_code : '',
|
||||
isset($info->avatar_urls) && is_array($info->avatar_urls) ? array_map(fn(mixed $item) => (is_object($item) ? V1UserAvatar::decode($item) : V1UserAvatar::empty()), $info->avatar_urls) : [],
|
||||
isset($info->profile_url) && is_string($info->profile_url) ? $info->profile_url : '',
|
||||
new DateTimeImmutable(isset($info->created_at) && is_string($info->created_at) ? $info->created_at : '@0'),
|
||||
isset($info->last_active_at) && is_string($info->last_active_at) ? new DateTimeImmutable($info->last_active_at) : null,
|
||||
isset($info->roles) && is_array($info->roles) ? $info->roles : [], // @phpstan-ignore-line
|
||||
isset($info->title) && is_string($info->title) ? $info->title : '',
|
||||
isset($info->super) && is_bool($info->super) ? $info->super : false,
|
||||
isset($info->deleted) && is_bool($info->deleted) ? $info->deleted : false
|
||||
);
|
||||
}
|
||||
}
|
70
src/V1/Users/V1UserAvatar.php
Normal file
70
src/V1/Users/V1UserAvatar.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php declare(strict_types=1);
|
||||
// V1UserAvatar.php
|
||||
// Created: 2024-11-16
|
||||
// Updated: 2024-11-16
|
||||
|
||||
namespace Flashii\V1\Users;
|
||||
|
||||
/**
|
||||
* Represents an APIv1 user avatar.
|
||||
*/
|
||||
final class V1UserAvatar {
|
||||
/**
|
||||
* @param int $res Width and height value of the avatar image.
|
||||
* @param string $url URI of the avatar image.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly int $res,
|
||||
private readonly string $url
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Checks whether this avatar image is the original upload (not guaranteed to be square).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOriginalImage(): bool {
|
||||
return $this->res === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width and height value of the avatar image.
|
||||
* 0 for the original image, possibly not a square.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getResolution(): int {
|
||||
return $this->res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets URI of the avatar image.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl(): string {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an object into this proper object.
|
||||
*
|
||||
* @param object $info
|
||||
* @return V1UserAvatar
|
||||
*/
|
||||
public static function decode(object $info): self {
|
||||
return new static(
|
||||
isset($info->res) && is_int($info->res) ? $info->res : 0,
|
||||
isset($info->url) && is_string($info->url) ? $info->url : ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a blank emote instance.
|
||||
*
|
||||
* @return V1UserAvatar
|
||||
*/
|
||||
public static function empty(): self {
|
||||
return new static(0, '');
|
||||
}
|
||||
}
|
56
src/V1/V1Client.php
Normal file
56
src/V1/V1Client.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php declare(strict_types=1);
|
||||
// V1Client.php
|
||||
// Created: 2024-11-16
|
||||
// Updated: 2024-11-16
|
||||
|
||||
namespace Flashii\V1;
|
||||
|
||||
use RuntimeException;
|
||||
use Flashii\FlashiiUrls;
|
||||
use Flashii\Http\HttpClient;
|
||||
use Flashii\V1\Emotes\V1EmotesClient;
|
||||
use Flashii\V1\Users\V1User;
|
||||
|
||||
/**
|
||||
* Implements the APIv1 client.
|
||||
*/
|
||||
class V1Client {
|
||||
private ?V1EmotesClient $emotes = null;
|
||||
|
||||
/**
|
||||
* @param HttpClient $httpClient HTTP client.
|
||||
* @param FlashiiUrls $urls API URLs.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly HttpClient $httpClient,
|
||||
private readonly FlashiiUrls $urls
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Returns information about the currently authenticated entity (user or app).
|
||||
*
|
||||
* @todo Currently there's no format for apps on the server side.
|
||||
* @throws RuntimeException If there is no authenticated entity.
|
||||
* @return V1User
|
||||
*/
|
||||
public function me(): V1User {
|
||||
$response = $this->httpClient->request('GET', $this->urls->getApiUrl('/v1/me'));
|
||||
$response->ensureSuccessStatusCode();
|
||||
|
||||
$me = $response->getJsonBody();
|
||||
if(!is_object($me))
|
||||
throw new RuntimeException('API response was not a JSON object.');
|
||||
|
||||
return V1User::decode($me);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the emotes portion of APIv1.
|
||||
*
|
||||
* @return V1EmotesClient
|
||||
*/
|
||||
public function emotes(): V1EmotesClient {
|
||||
$this->emotes ??= new V1EmotesClient($this->httpClient, $this->urls);
|
||||
return $this->emotes;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue