Removed RPCii dependency.
This commit is contained in:
parent
6c50a582cb
commit
0b7031959b
10 changed files with 2 additions and 485 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
20250325.2
|
||||
20250325.3
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
"php": ">=8.4",
|
||||
"ext-mbstring": "*",
|
||||
"flashwave/index": "^0.2503",
|
||||
"flashii/rpcii": "~5.0",
|
||||
"erusev/parsedown": "~1.7",
|
||||
"chillerlan/php-qrcode": "~5.0",
|
||||
"symfony/mailer": "~7.2",
|
||||
|
|
43
composer.lock
generated
43
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "baa15cf491eb4500360fa9c20fd42a4d",
|
||||
"content-hash": "cd96df7b2981a653c33b100a8b3837cd",
|
||||
"packages": [
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
|
@ -499,47 +499,6 @@
|
|||
],
|
||||
"time": "2025-03-15T12:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "flashii/rpcii",
|
||||
"version": "v5.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://patchii.net/flashii/rpcii-php.git",
|
||||
"reference": "28c25e0a342173524f8894d03158663842e03252"
|
||||
},
|
||||
"require": {
|
||||
"ext-msgpack": ">=2.2",
|
||||
"flashwave/index": "^0.2503",
|
||||
"guzzlehttp/guzzle": "~7.0",
|
||||
"php": ">=8.4",
|
||||
"psr/http-client": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpunit/phpunit": "^12.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"RPCii\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"bsd-3-clause-clear"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "flashwave",
|
||||
"email": "packagist@flash.moe",
|
||||
"homepage": "https://flash.moe",
|
||||
"role": "mom"
|
||||
}
|
||||
],
|
||||
"description": "HTTP RPC client/server library.",
|
||||
"homepage": "https://railgun.sh/rpcii",
|
||||
"time": "2025-03-21T19:38:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "flashwave/index",
|
||||
"version": "v0.2503.251417",
|
||||
|
|
|
@ -12,7 +12,6 @@ Below are a number of links to source code repositories related to Flashii.net a
|
|||
- [Uiharu](https://patchii.net/flashii/uiharu): Service for looking up URL metadata.
|
||||
- [Seria](https://patchii.net/flashii/seria): Software used by the downloads tracker.
|
||||
- [Mince](https://patchii.net/flashii/mince): Source code for the Minecraft servers subwebsite.
|
||||
- [Aleister](https://patchii.net/flashii/aleister): Public API gateway.
|
||||
|
||||
## Tools & Software
|
||||
- [SoFii](https://patchii.net/flashii/sofii): Launcher for Soldier of Fortune 2
|
||||
|
@ -21,7 +20,6 @@ Below are a number of links to source code repositories related to Flashii.net a
|
|||
|
||||
## First-Party Libraries
|
||||
- [Index](https://patchii.net/flash/index): Base library used in almost any component of the website that uses PHP.
|
||||
- [RPCii](https://patchii.net/flashii/rpcii): Internal RPC extension, mainly used to supply data to the API gateway.
|
||||
|
||||
## Historical
|
||||
- [AJAX Chat (fork)](https://patchii.net/flashii/ajax-chat): Old chat software (2013-2015). Still kept on life support for the nostalgia.
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\Auth;
|
||||
|
||||
use RuntimeException;
|
||||
use Misuzu\Users\{UsersContext,UserInfo};
|
||||
use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcAction};
|
||||
use Index\Config\Config;
|
||||
|
||||
final class AuthRpcHandler implements RpcHandler {
|
||||
use RpcHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private Config $impersonateConfig,
|
||||
private UsersContext $usersCtx,
|
||||
private AuthContext $authCtx
|
||||
) {}
|
||||
|
||||
private function canImpersonateUserId(UserInfo $impersonator, string $targetId): bool {
|
||||
if($impersonator->super)
|
||||
return true;
|
||||
|
||||
$whitelist = $this->impersonateConfig->getArray(sprintf('allow.u%s', $impersonator->id));
|
||||
return in_array($targetId, $whitelist, true);
|
||||
}
|
||||
|
||||
/** @return array{method: string, error: string}|array{method: string, type: string, user: string, expires: int} */
|
||||
#[RpcAction('misuzu:auth:attemptMisuzuAuth')]
|
||||
public function procAttemptMisuzuAuth(string $remoteAddr, string $token): array {
|
||||
$tokenInfo = $this->authCtx->createAuthTokenPacker()->unpack($token);
|
||||
if(!$tokenInfo->isEmpty)
|
||||
$token = $tokenInfo->sessionToken;
|
||||
|
||||
try {
|
||||
$sessionInfo = $this->authCtx->sessions->getSession(sessionToken: $token);
|
||||
} catch(RuntimeException $ex) {
|
||||
return ['method' => 'misuzu', 'error' => 'token'];
|
||||
}
|
||||
|
||||
if($sessionInfo->expired) {
|
||||
$this->authCtx->sessions->deleteSessions(sessionInfos: $sessionInfo);
|
||||
return ['method' => 'misuzu', 'error' => 'expired'];
|
||||
}
|
||||
|
||||
$this->authCtx->sessions->recordSessionActivity(sessionInfo: $sessionInfo, remoteAddr: $remoteAddr);
|
||||
|
||||
$userInfo = $this->usersCtx->users->getUser($sessionInfo->userId, 'id');
|
||||
if($tokenInfo->hasImpersonatedUserId && $this->canImpersonateUserId($userInfo, $tokenInfo->impersonatedUserId)) {
|
||||
$userInfoReal = $userInfo;
|
||||
|
||||
try {
|
||||
$userInfo = $this->usersCtx->users->getUser($tokenInfo->impersonatedUserId, 'id');
|
||||
} catch(RuntimeException $ex) {
|
||||
$userInfo = $userInfoReal;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'method' => 'misuzu',
|
||||
'type' => 'user',
|
||||
'user' => $userInfo->id,
|
||||
'expires' => $sessionInfo->expiresTime,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\Emoticons;
|
||||
|
||||
use Index\XArray;
|
||||
use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcQuery};
|
||||
|
||||
final class EmotesRpcHandler implements RpcHandler {
|
||||
use RpcHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private EmotesData $emotes
|
||||
) {}
|
||||
|
||||
/** @return array<array{url: string, strings: string[], id?: string, order?: int, min_rank?: int}> */
|
||||
#[RpcQuery('misuzu:emotes:all')]
|
||||
public function queryAll(bool $includeId = false, bool $includeOrder = false): array {
|
||||
return XArray::select(
|
||||
$this->emotes->getEmotes(orderBy: 'order'),
|
||||
function($emote) use ($includeId, $includeOrder) {
|
||||
$info = [
|
||||
'url' => $emote->url,
|
||||
'strings' => XArray::select(
|
||||
$this->emotes->getEmoteStrings($emote),
|
||||
fn($string) => $string->string
|
||||
),
|
||||
];
|
||||
|
||||
if($includeId)
|
||||
$info['id'] = $emote->id;
|
||||
if($includeOrder)
|
||||
$info['order'] = $emote->order;
|
||||
|
||||
$rank = $emote->minRank;
|
||||
if($rank !== 0)
|
||||
$info['min_rank'] = $rank;
|
||||
|
||||
return $info;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ use Index\Http\Routing\Routes\{ExactRoute,PatternRoute};
|
|||
use Index\Urls\{UrlFormat,UrlSource,UrlSourceCommon};
|
||||
use Misuzu\{Misuzu,Template};
|
||||
use Misuzu\Parsers\{Parsers,TextFormat};
|
||||
use RPCii\RPCii;
|
||||
|
||||
class InfoRoutes implements RouteHandler, UrlSource {
|
||||
use RouteHandlerCommon, UrlSourceCommon;
|
||||
|
@ -16,12 +15,10 @@ class InfoRoutes implements RouteHandler, UrlSource {
|
|||
private const PROJECT_PATHS = [
|
||||
'misuzu' => Misuzu::PATH_ROOT,
|
||||
'index' => Index::PATH_ROOT,
|
||||
'rpcii' => RPCii::PATH_ROOT,
|
||||
];
|
||||
private const PROJECT_SUFFIXES = [
|
||||
'misuzu' => 'Misuzu » %s',
|
||||
'index' => 'Index » %s',
|
||||
'rpcii' => 'RPCii » %s',
|
||||
];
|
||||
|
||||
#[ExactRoute('GET', '/info')]
|
||||
|
|
|
@ -11,8 +11,6 @@ use Index\Templating\TplEnvironment;
|
|||
use Index\Urls\UrlRegistry;
|
||||
use Misuzu\Routing\RoutingContext;
|
||||
use Misuzu\Users\UserInfo;
|
||||
use RPCii\HmacVerificationProvider;
|
||||
use RPCii\Server\{HttpRpcServer,RpcServer};
|
||||
|
||||
class MisuzuContext {
|
||||
public private(set) Dependencies $deps;
|
||||
|
@ -158,11 +156,6 @@ class MisuzuContext {
|
|||
public function registerMainRoutes(
|
||||
RoutingContext $routingCtx
|
||||
): void {
|
||||
$rpcServer = new HttpRpcServer;
|
||||
$routingCtx->register($rpcServer->createRouteHandler(
|
||||
new HmacVerificationProvider(fn() => $this->config->getString('aleister.secret'))
|
||||
));
|
||||
|
||||
$this->deps->register($wf = new WebFinger\WebFingerRegistry);
|
||||
$wf->register($this->deps->constructLazy(
|
||||
Users\UsersWebFingerResolver::class,
|
||||
|
@ -190,7 +183,6 @@ class MisuzuContext {
|
|||
|
||||
$routingCtx->register($this->deps->constructLazy(OAuth2\OAuth2ApiRoutes::class));
|
||||
$routingCtx->register($this->deps->constructLazy(OAuth2\OAuth2WebRoutes::class));
|
||||
$rpcServer->register($this->deps->constructLazy(OAuth2\OAuth2RpcHandler::class));
|
||||
$routingCtx->register($this->deps->constructLazy(WebFinger\WebFingerRoutes::class));
|
||||
|
||||
$routingCtx->register($this->deps->constructLazy(Forum\ForumCategoriesRoutes::class));
|
||||
|
@ -210,13 +202,6 @@ class MisuzuContext {
|
|||
));
|
||||
|
||||
$routingCtx->register($this->deps->constructLazy(LegacyRoutes::class));
|
||||
|
||||
$rpcServer->register($this->deps->constructLazy(
|
||||
Auth\AuthRpcHandler::class,
|
||||
impersonateConfig: $this->config->scopeTo('impersonate')
|
||||
));
|
||||
$rpcServer->register($this->deps->constructLazy(Emoticons\EmotesRpcHandler::class));
|
||||
$rpcServer->register($this->deps->constructLazy(Users\UsersRpcHandler::class));
|
||||
}
|
||||
|
||||
public function registerRedirectorRoutes(RoutingContext $routingCtx): void {
|
||||
|
|
|
@ -1,196 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\OAuth2;
|
||||
|
||||
use RuntimeException;
|
||||
use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcAction};
|
||||
|
||||
final class OAuth2RpcHandler implements RpcHandler {
|
||||
use RpcHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private OAuth2Context $oauth2Ctx
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* method: 'basic',
|
||||
* error?: 'app'|'secret',
|
||||
* type?: 'confapp'|'pubapp',
|
||||
* app?: string,
|
||||
* scope?: string[]
|
||||
* }
|
||||
*/
|
||||
#[RpcAction('hanyuu:oauth2:attemptAppAuth')]
|
||||
public function procAttemptAppAuth(string $remoteAddr, string $clientId, string $clientSecret = ''): array {
|
||||
try {
|
||||
$appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(clientId: $clientId, deleted: false);
|
||||
} catch(RuntimeException $ex) {
|
||||
return ['method' => 'basic', 'error' => 'app'];
|
||||
}
|
||||
|
||||
$authed = false;
|
||||
if($clientSecret !== '') {
|
||||
// TODO: rate limiting
|
||||
|
||||
if(!$appInfo->verifyClientSecret($clientSecret))
|
||||
return ['method' => 'basic', 'error' => 'secret'];
|
||||
|
||||
$authed = true;
|
||||
}
|
||||
|
||||
return [
|
||||
'method' => 'basic',
|
||||
'type' => $authed ? 'confapp' : 'pubapp',
|
||||
'app' => $appInfo->id,
|
||||
'scope' => ['oauth2'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* method: 'bearer',
|
||||
* error?: 'token'|'expired',
|
||||
* type?: 'app'|'user',
|
||||
* app?: string,
|
||||
* user?: string,
|
||||
* scope?: string[],
|
||||
* expires?: int,
|
||||
* }
|
||||
*/
|
||||
#[RpcAction('hanyuu:oauth2:attemptBearerAuth')]
|
||||
public function procAttemptBearerAuth(string $remoteAddr, string $token): array {
|
||||
try {
|
||||
$tokenInfo = $this->oauth2Ctx->tokens->getAccessInfo($token, OAuth2AccessInfoGetField::Token);
|
||||
} catch(RuntimeException $ex) {
|
||||
return ['method' => 'bearer', 'error' => 'token'];
|
||||
}
|
||||
|
||||
if($tokenInfo->expired)
|
||||
return ['method' => 'bearer', 'error' => 'expired'];
|
||||
|
||||
return [
|
||||
'method' => 'bearer',
|
||||
'type' => empty($tokenInfo->userId) ? 'app' : 'user',
|
||||
'app' => $tokenInfo->appId,
|
||||
'user' => $tokenInfo->userId ?? '0',
|
||||
'scope' => $tokenInfo->scopes,
|
||||
'expires' => $tokenInfo->expiresTime,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* device_code: string,
|
||||
* user_code: string,
|
||||
* verification_uri: string,
|
||||
* verification_uri_complete: string,
|
||||
* expires_in?: int,
|
||||
* interval?: int
|
||||
* }|array{ error: string, error_description: string }
|
||||
*/
|
||||
#[RpcAction('hanyuu:oauth2:createAuthoriseRequest')]
|
||||
public function procCreateAuthoriseRequest(string $appId, ?string $scope = null): array {
|
||||
try {
|
||||
$appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false);
|
||||
} catch(RuntimeException $ex) {
|
||||
return [
|
||||
'error' => 'invalid_client',
|
||||
'error_description' => 'No application has been registered with this client ID.',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->oauth2Ctx->createDeviceAuthorisationRequest($appInfo, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* access_token: string,
|
||||
* token_type: 'Bearer',
|
||||
* expires_in?: int,
|
||||
* scope?: string,
|
||||
* refresh_token?: string,
|
||||
* }|array{ error: string, error_description: string }
|
||||
*/
|
||||
#[RpcAction('hanyuu:oauth2:createBearerToken:authorisationCode')]
|
||||
public function procCreateBearerTokenAuthzCode(string $appId, bool $isAuthed, string $code, string $codeVerifier): array {
|
||||
try {
|
||||
$appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false);
|
||||
} catch(RuntimeException $ex) {
|
||||
return [
|
||||
'error' => 'invalid_client',
|
||||
'error_description' => 'No application has been registered with this client ID.',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->oauth2Ctx->redeemAuthorisationCode($appInfo, $isAuthed, $code, $codeVerifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* access_token: string,
|
||||
* token_type: 'Bearer',
|
||||
* expires_in?: int,
|
||||
* scope?: string,
|
||||
* refresh_token?: string,
|
||||
* }|array{ error: string, error_description: string }
|
||||
*/
|
||||
#[RpcAction('hanyuu:oauth2:createBearerToken:refreshToken')]
|
||||
public function procCreateBearerTokenRefreshToken(string $appId, bool $isAuthed, string $refreshToken, ?string $scope = null): array {
|
||||
try {
|
||||
$appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false);
|
||||
} catch(RuntimeException $ex) {
|
||||
return [
|
||||
'error' => 'invalid_client',
|
||||
'error_description' => 'No application has been registered with this client ID.',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->oauth2Ctx->redeemRefreshToken($appInfo, $isAuthed, $refreshToken, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* access_token: string,
|
||||
* token_type: 'Bearer',
|
||||
* expires_in?: int,
|
||||
* scope?: string,
|
||||
* refresh_token?: string,
|
||||
* }|array{ error: string, error_description: string }
|
||||
*/
|
||||
#[RpcAction('hanyuu:oauth2:createBearerToken:clientCredentials')]
|
||||
public function procCreateBearerTokenClientCreds(string $appId, bool $isAuthed, ?string $scope = null): array {
|
||||
try {
|
||||
$appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false);
|
||||
} catch(RuntimeException $ex) {
|
||||
return [
|
||||
'error' => 'invalid_client',
|
||||
'error_description' => 'No application has been registered with this client ID.',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->oauth2Ctx->redeemClientCredentials($appInfo, $isAuthed, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* access_token: string,
|
||||
* token_type: 'Bearer',
|
||||
* expires_in?: int,
|
||||
* scope?: string,
|
||||
* refresh_token?: string,
|
||||
* }|array{ error: string, error_description: string }
|
||||
*/
|
||||
#[RpcAction('hanyuu:oauth2:createBearerToken:deviceCode')]
|
||||
public function procCreateBearerTokenDeviceCode(string $appId, bool $isAuthed, string $deviceCode): array {
|
||||
try {
|
||||
$appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false);
|
||||
} catch(RuntimeException $ex) {
|
||||
return [
|
||||
'error' => 'invalid_client',
|
||||
'error_description' => 'No application has been registered with this client ID.',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->oauth2Ctx->redeemDeviceCode($appInfo, $isAuthed, $deviceCode);
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use RuntimeException;
|
||||
use Misuzu\SiteInfo;
|
||||
use Misuzu\Users\Assets\UserAvatarAsset;
|
||||
use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcQuery};
|
||||
use Index\XArray;
|
||||
use Index\Colour\{Colour,ColourRgb};
|
||||
use Index\Urls\UrlRegistry;
|
||||
|
||||
final class UsersRpcHandler implements RpcHandler {
|
||||
use RpcHandlerCommon;
|
||||
|
||||
public function __construct(
|
||||
private SiteInfo $siteInfo,
|
||||
private UrlRegistry $urls,
|
||||
private UsersContext $usersCtx
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array{error: string}|array{
|
||||
* id: string,
|
||||
* name: string,
|
||||
* email?: string,
|
||||
* colour_raw: int,
|
||||
* colour_css: string,
|
||||
* rank: int,
|
||||
* country_code: string,
|
||||
* roles?: string[],
|
||||
* is_super?: bool,
|
||||
* title?: string,
|
||||
* created_at: string,
|
||||
* last_active_at?: string,
|
||||
* profile_url: string,
|
||||
* avatar_url: string,
|
||||
* avatar_urls?: array{res: int, url: string}[],
|
||||
* is_deleted?: bool
|
||||
* }
|
||||
*/
|
||||
#[RpcQuery('misuzu:users:getUser')]
|
||||
public function queryGetUser(string $userId, bool $includeEMailAddress = false): array {
|
||||
try {
|
||||
$userInfo = $this->usersCtx->getUserInfo($userId, UsersData::GET_USER_ID);
|
||||
} catch(RuntimeException) {
|
||||
return ['error' => 'notfound'];
|
||||
}
|
||||
|
||||
// TODO: there should be some kinda privacy controls for users
|
||||
|
||||
|
||||
$colour = $this->usersCtx->getUserColour($userInfo);
|
||||
if($colour->inherits) {
|
||||
$colourRaw = null;
|
||||
$colourCSS = (string)$colour;
|
||||
} else {
|
||||
$colourRaw = Colour::toRawRgb($colour);
|
||||
$colourCSS = (string)ColourRgb::convert($colour);
|
||||
}
|
||||
|
||||
$baseUrl = $this->siteInfo->url;
|
||||
|
||||
$output = [];
|
||||
|
||||
$output['id'] = $userInfo->id;
|
||||
$output['name'] = $userInfo->name;
|
||||
if($includeEMailAddress)
|
||||
$output['email'] = $userInfo->emailAddress;
|
||||
|
||||
$output['colour_raw'] = $colourRaw;
|
||||
$output['colour_css'] = $colourCSS;
|
||||
$output['country_code'] = $userInfo->countryCode;
|
||||
|
||||
if($this->usersCtx->hasActiveBan($userInfo)) {
|
||||
$output['rank'] = 0;
|
||||
$output['roles'] = ['x-banned'];
|
||||
} else {
|
||||
$roles = XArray::select(
|
||||
$this->usersCtx->roles->getRoles(userInfo: $userInfo, hasString: true, orderByRank: true),
|
||||
fn($roleInfo) => $roleInfo->string,
|
||||
);
|
||||
|
||||
$output['rank'] = $this->usersCtx->getUserRank($userInfo);
|
||||
if(!empty($roles))
|
||||
$output['roles'] = $roles;
|
||||
if($userInfo->super)
|
||||
$output['is_super'] = true;
|
||||
}
|
||||
|
||||
if(!empty($userInfo->title))
|
||||
$output['title'] = $userInfo->title;
|
||||
|
||||
$output['created_at'] = $userInfo->createdAt->toIso8601ZuluString();
|
||||
if($userInfo->lastActiveTime !== null)
|
||||
$output['last_active_at'] = $userInfo->lastActiveAt->toIso8601ZuluString();
|
||||
|
||||
$output['profile_url'] = $baseUrl . $this->urls->format('user-profile', ['user' => $userInfo->id]);
|
||||
$output['avatar_url'] = $baseUrl . $this->urls->format('user-avatar', ['user' => $userInfo->id]);
|
||||
|
||||
/* Remove the following later */
|
||||
$avatars = [];
|
||||
$formatAvatarUrl = fn($res = 0) => (
|
||||
$baseUrl . $this->urls->format('user-avatar', ['user' => $userInfo->id, 'res' => $res])
|
||||
);
|
||||
|
||||
$avatars[] = ['res' => 0, 'url' => $formatAvatarUrl()];
|
||||
foreach(UserAvatarAsset::DIMENSIONS as $res)
|
||||
$avatars[] = ['res' => $res, 'url' => $formatAvatarUrl($res)];
|
||||
|
||||
$avatars = array_reverse($avatars);
|
||||
|
||||
$output['avatar_urls'] = $avatars;
|
||||
/* / */
|
||||
|
||||
if($userInfo->deleted)
|
||||
$output['is_deleted'] = true;
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue