2019-05-09 18:54:39 +12:00
< ? php
2022-05-03 06:06:12 +12:00
use Appwrite\Extend\Exception ;
2023-01-14 04:28:04 +13:00
use Utopia\Validator\URL ;
2021-02-20 02:59:46 +13:00
use Appwrite\URL\URL as URLParse ;
use Appwrite\Utopia\Response ;
use chillerlan\QRCode\QRCode ;
use chillerlan\QRCode\QROptions ;
2020-06-29 05:31:21 +12:00
use Utopia\App ;
2023-04-29 23:33:38 +12:00
use Utopia\CLI\Console ;
2021-02-20 02:59:46 +13:00
use Utopia\Config\Config ;
2023-04-19 19:25:05 +12:00
use Utopia\Database\Database ;
use Utopia\Database\DateTime ;
2022-05-03 06:06:12 +12:00
use Utopia\Database\Document ;
2023-04-26 20:21:10 +12:00
use Utopia\Database\Validator\Authorization ;
use Utopia\Database\Validator\UID ;
2021-02-20 02:59:46 +13:00
use Utopia\Image\Image ;
2023-04-29 23:33:38 +12:00
use Utopia\Logger\Log ;
use Utopia\Logger\Logger ;
2020-06-22 00:18:00 +12:00
use Utopia\Validator\Boolean ;
2021-02-20 02:59:46 +13:00
use Utopia\Validator\HexColor ;
2019-05-09 18:54:39 +12:00
use Utopia\Validator\Range ;
2021-02-20 02:59:46 +13:00
use Utopia\Validator\Text ;
use Utopia\Validator\WhiteList ;
2019-05-09 18:54:39 +12:00
2022-07-08 02:51:22 +12:00
$avatarCallback = function ( string $type , string $code , int $width , int $height , int $quality , Response $response ) {
2020-06-30 09:43:34 +12:00
2020-06-20 23:20:49 +12:00
$code = \strtolower ( $code );
$type = \strtolower ( $type );
2021-02-20 02:59:46 +13:00
$set = Config :: getParam ( 'avatar-' . $type , []);
2019-05-09 18:54:39 +12:00
2020-06-27 17:36:22 +12:00
if ( empty ( $set )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: AVATAR_SET_NOT_FOUND );
2019-05-09 18:54:39 +12:00
}
2020-06-27 17:36:22 +12:00
if ( ! \array_key_exists ( $code , $set )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: AVATAR_NOT_FOUND );
2019-05-09 18:54:39 +12:00
}
2020-06-20 23:20:49 +12:00
if ( ! \extension_loaded ( 'imagick' )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Imagick extension is missing' );
2019-05-09 18:54:39 +12:00
}
2019-09-07 05:10:41 +12:00
$output = 'png' ;
2020-06-27 17:36:22 +12:00
$path = $set [ $code ];
2019-09-07 05:10:41 +12:00
$type = 'png' ;
2019-05-09 18:54:39 +12:00
2020-06-20 23:20:49 +12:00
if ( ! \is_readable ( $path )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'File not readable in ' . $path );
2019-05-09 18:54:39 +12:00
}
2021-02-20 02:59:46 +13:00
$image = new Image ( \file_get_contents ( $path ));
$image -> crop (( int ) $width , ( int ) $height );
2019-05-09 18:54:39 +12:00
$output = ( empty ( $output )) ? $type : $output ;
2021-02-20 02:59:46 +13:00
$data = $image -> output ( $output , $quality );
2022-07-24 21:49:51 +12:00
$response
2022-07-29 03:24:18 +12:00
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + 60 * 60 * 24 * 30 ) . ' GMT' )
2022-07-24 21:49:51 +12:00
-> setContentType ( 'image/png' )
2023-04-19 19:25:05 +12:00
-> file ( $data );
2021-02-20 02:59:46 +13:00
unset ( $image );
2019-05-09 18:54:39 +12:00
};
2023-04-29 23:33:38 +12:00
$getUserGitHub = function ( string $userId , Document $project , Database $dbForProject , Database $dbForConsole , ? Logger $logger ) {
2023-04-26 20:21:10 +12:00
try {
2023-04-28 19:30:30 +12:00
$user = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'users' , $userId ));
2023-04-26 20:21:10 +12:00
$sessions = $user -> getAttribute ( 'sessions' , []);
2023-04-29 23:33:38 +12:00
$gitHubSession = null ;
foreach ( $sessions as $session ) {
if ( $session -> getAttribute ( 'provider' , '' ) === 'github' ) {
$gitHubSession = $session ;
break ;
}
}
if ( empty ( $gitHubSession )) {
throw new Exception ( Exception :: GENERAL_UNKNOWN , 'GitHub session not found.' );
}
$provider = $gitHubSession -> getAttribute ( 'provider' , '' );
$accessToken = $gitHubSession -> getAttribute ( 'providerAccessToken' );
$accessTokenExpiry = $gitHubSession -> getAttribute ( 'providerAccessTokenExpiry' );
$refreshToken = $gitHubSession -> getAttribute ( 'providerRefreshToken' );
2023-04-26 20:21:10 +12:00
$appId = $project -> getAttribute ( 'authProviders' , [])[ $provider . 'Appid' ] ? ? '' ;
$appSecret = $project -> getAttribute ( 'authProviders' , [])[ $provider . 'Secret' ] ? ? '{}' ;
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst ( $provider );
if ( ! \class_exists ( $className )) {
throw new Exception ( Exception :: PROJECT_PROVIDER_UNSUPPORTED );
}
$oauth2 = new $className ( $appId , $appSecret , '' , [], []);
2023-04-28 19:30:30 +12:00
$isExpired = new \DateTime ( $accessTokenExpiry ) < new \DateTime ( 'now' );
if ( $isExpired ) {
try {
$oauth2 -> refreshTokens ( $refreshToken );
$accessToken = $oauth2 -> getAccessToken ( '' );
$refreshToken = $oauth2 -> getRefreshToken ( '' );
2023-04-28 21:07:26 +12:00
$verificationId = $oauth2 -> getUserID ( $accessToken );
if ( empty ( $verificationId )) {
throw new \Exception ( " Locked tokens. " ); // Race codition, handeled in catch
2023-04-28 19:30:30 +12:00
}
2023-04-26 20:21:10 +12:00
2023-04-29 23:33:38 +12:00
$gitHubSession
2023-04-28 19:30:30 +12:00
-> setAttribute ( 'providerAccessToken' , $accessToken )
-> setAttribute ( 'providerRefreshToken' , $refreshToken )
-> setAttribute ( 'providerAccessTokenExpiry' , DateTime :: addSeconds ( new \DateTime (), ( int ) $oauth2 -> getAccessTokenExpiry ( '' )));
2023-04-26 20:21:10 +12:00
2023-04-29 23:33:38 +12:00
Authorization :: skip ( fn () => $dbForProject -> updateDocument ( 'sessions' , $gitHubSession -> getId (), $gitHubSession ));
2023-04-26 20:21:10 +12:00
2023-04-28 19:30:30 +12:00
$dbForProject -> deleteCachedDocument ( 'users' , $user -> getId ());
} catch ( Throwable $err ) {
$index = 0 ;
do {
2023-04-29 23:33:38 +12:00
$previousAccessToken = $gitHubSession -> getAttribute ( 'providerAccessToken' );
2023-04-26 20:21:10 +12:00
2023-04-28 19:30:30 +12:00
$user = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'users' , $userId ));
$sessions = $user -> getAttribute ( 'sessions' , []);
2023-04-29 23:33:38 +12:00
$gitHubSession = new Document ();
foreach ( $sessions as $session ) {
if ( $session -> getAttribute ( 'provider' , '' ) === 'github' ) {
$gitHubSession = $session ;
break ;
}
}
$accessToken = $gitHubSession -> getAttribute ( 'providerAccessToken' );
2023-04-28 19:30:30 +12:00
2023-04-28 21:07:26 +12:00
if ( $accessToken !== $previousAccessToken ) {
2023-04-28 19:30:30 +12:00
break ;
}
$index ++ ;
2023-04-28 21:07:26 +12:00
\usleep ( 500000 );
2023-04-28 19:30:30 +12:00
} while ( $index < 10 );
}
2023-04-26 23:51:19 +12:00
}
2023-04-26 20:21:10 +12:00
2023-04-28 21:07:26 +12:00
$oauth2 = new $className ( $appId , $appSecret , '' , [], []);
2023-04-26 20:21:10 +12:00
$githubUser = $oauth2 -> getUserSlug ( $accessToken );
$githubId = $oauth2 -> getUserID ( $accessToken );
return [
'name' => $githubUser ,
'id' => $githubId
];
2023-04-29 23:33:38 +12:00
} catch ( Exception $error ) {
if ( $logger ) {
$version = App :: getEnv ( '_APP_VERSION' , 'UNKNOWN' );
$log = new Log ();
$log -> setNamespace ( 'console' );
$log -> setServer ( \gethostname ());
$log -> setVersion ( $version );
$log -> setType ( Log :: TYPE_ERROR );
$log -> setMessage ( $error -> getMessage ());
$log -> addTag ( 'code' , $error -> getCode ());
$log -> addTag ( 'verboseType' , get_class ( $error ));
$log -> addExtra ( 'file' , $error -> getFile ());
$log -> addExtra ( 'line' , $error -> getLine ());
$log -> addExtra ( 'trace' , $error -> getTraceAsString ());
$log -> addExtra ( 'detailedTrace' , $error -> getTrace ());
$log -> setAction ( 'avatarsGetGitHub' );
$isProduction = App :: getEnv ( '_APP_ENV' , 'development' ) === 'production' ;
$log -> setEnvironment ( $isProduction ? Log :: ENVIRONMENT_PRODUCTION : Log :: ENVIRONMENT_STAGING );
$responseCode = $logger -> addLog ( $log );
Console :: info ( 'GitHub error log pushed with status code: ' . $responseCode );
}
Console :: warning ( " Failed: { $error -> getMessage () } " );
Console :: warning ( $error -> getTraceAsString ());
2023-04-26 20:21:10 +12:00
return [];
}
2023-04-29 23:33:38 +12:00
return [];
2023-04-26 20:21:10 +12:00
};
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/avatars/credit-cards/:code' )
2019-05-09 18:54:39 +12:00
-> desc ( 'Get Credit Card Icon' )
2022-07-24 19:05:24 +12:00
-> groups ([ 'api' , 'avatars' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'avatars.read' )
2022-08-17 21:25:47 +12:00
-> label ( 'cache' , true )
2022-08-16 01:55:11 +12:00
-> label ( 'cache.resource' , 'avatar/credit-card' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'avatars' )
-> label ( 'sdk.method' , 'getCreditCard' )
2020-05-18 16:26:28 +12:00
-> label ( 'sdk.methodType' , 'location' )
2019-10-09 21:31:51 +13:00
-> label ( 'sdk.description' , '/docs/references/avatars/get-credit-card.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
2020-11-12 11:02:02 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_IMAGE_PNG )
2021-02-20 02:59:46 +13:00
-> param ( 'code' , '' , new WhiteList ( \array_keys ( Config :: getParam ( 'avatar-credit-cards' ))), 'Credit Card Code. Possible values: ' . \implode ( ', ' , \array_keys ( Config :: getParam ( 'avatar-credit-cards' ))) . '.' )
2022-04-20 20:27:28 +12:00
-> param ( 'width' , 100 , new Range ( 0 , 2000 ), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.' , true )
-> param ( 'height' , 100 , new Range ( 0 , 2000 ), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.' , true )
2020-09-11 02:40:14 +12:00
-> param ( 'quality' , 100 , new Range ( 0 , 100 ), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.' , true )
2020-12-27 03:59:15 +13:00
-> inject ( 'response' )
2022-07-08 02:51:22 +12:00
-> action ( fn ( string $code , int $width , int $height , int $quality , Response $response ) => $avatarCallback ( 'credit-cards' , $code , $width , $height , $quality , $response ));
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/avatars/browsers/:code' )
2019-05-09 18:54:39 +12:00
-> desc ( 'Get Browser Icon' )
2022-07-24 19:05:24 +12:00
-> groups ([ 'api' , 'avatars' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'avatars.read' )
2022-08-17 21:25:47 +12:00
-> label ( 'cache' , true )
2022-08-16 01:55:11 +12:00
-> label ( 'cache.resource' , 'avatar/browser' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'avatars' )
-> label ( 'sdk.method' , 'getBrowser' )
2020-05-25 15:36:10 +12:00
-> label ( 'sdk.methodType' , 'location' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/avatars/get-browser.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
2020-11-12 11:02:02 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_IMAGE_PNG )
2020-09-11 02:40:14 +12:00
-> param ( 'code' , '' , new WhiteList ( \array_keys ( Config :: getParam ( 'avatar-browsers' ))), 'Browser Code.' )
2022-04-20 20:27:28 +12:00
-> param ( 'width' , 100 , new Range ( 0 , 2000 ), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.' , true )
-> param ( 'height' , 100 , new Range ( 0 , 2000 ), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.' , true )
2020-09-11 02:40:14 +12:00
-> param ( 'quality' , 100 , new Range ( 0 , 100 ), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.' , true )
2020-12-27 03:59:15 +13:00
-> inject ( 'response' )
2022-07-08 02:51:22 +12:00
-> action ( fn ( string $code , int $width , int $height , int $quality , Response $response ) => $avatarCallback ( 'browsers' , $code , $width , $height , $quality , $response ));
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/avatars/flags/:code' )
2019-05-09 18:54:39 +12:00
-> desc ( 'Get Country Flag' )
2022-07-24 19:05:24 +12:00
-> groups ([ 'api' , 'avatars' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'avatars.read' )
2022-08-17 21:25:47 +12:00
-> label ( 'cache' , true )
2022-08-16 01:55:11 +12:00
-> label ( 'cache.resource' , 'avatar/flag' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'avatars' )
-> label ( 'sdk.method' , 'getFlag' )
2020-05-18 16:26:28 +12:00
-> label ( 'sdk.methodType' , 'location' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/avatars/get-flag.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
2020-11-12 11:02:02 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_IMAGE_PNG )
2020-09-11 02:40:14 +12:00
-> param ( 'code' , '' , new WhiteList ( \array_keys ( Config :: getParam ( 'avatar-flags' ))), 'Country Code. ISO Alpha-2 country code format.' )
2022-04-20 20:31:12 +12:00
-> param ( 'width' , 100 , new Range ( 0 , 2000 ), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.' , true )
-> param ( 'height' , 100 , new Range ( 0 , 2000 ), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.' , true )
2020-09-11 02:40:14 +12:00
-> param ( 'quality' , 100 , new Range ( 0 , 100 ), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.' , true )
2020-12-27 03:59:15 +13:00
-> inject ( 'response' )
2022-07-08 02:51:22 +12:00
-> action ( fn ( string $code , int $width , int $height , int $quality , Response $response ) => $avatarCallback ( 'flags' , $code , $width , $height , $quality , $response ));
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/avatars/image' )
2019-08-24 02:16:25 +12:00
-> desc ( 'Get Image from URL' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'avatars' ])
2019-07-10 08:20:39 +12:00
-> label ( 'scope' , 'avatars.read' )
2022-08-17 21:25:47 +12:00
-> label ( 'cache' , true )
2022-08-16 01:55:11 +12:00
-> label ( 'cache.resource' , 'avatar/image' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2019-07-10 08:20:39 +12:00
-> label ( 'sdk.namespace' , 'avatars' )
-> label ( 'sdk.method' , 'getImage' )
2020-05-18 16:26:28 +12:00
-> label ( 'sdk.methodType' , 'location' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/avatars/get-image.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
2020-11-12 11:02:02 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_IMAGE )
2022-02-17 04:16:37 +13:00
-> param ( 'url' , '' , new URL ([ 'http' , 'https' ]), 'Image URL which you want to crop.' )
2022-04-20 20:31:12 +12:00
-> param ( 'width' , 400 , new Range ( 0 , 2000 ), 'Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.' , true )
-> param ( 'height' , 400 , new Range ( 0 , 2000 ), 'Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.' , true )
2020-12-27 03:59:15 +13:00
-> inject ( 'response' )
2022-07-08 02:51:22 +12:00
-> action ( function ( string $url , int $width , int $height , Response $response ) {
2020-06-30 09:43:34 +12:00
$quality = 80 ;
$output = 'png' ;
$type = 'png' ;
2022-07-24 05:42:42 +12:00
2020-06-30 09:43:34 +12:00
if ( ! \extension_loaded ( 'imagick' )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Imagick extension is missing' );
2020-06-30 09:43:34 +12:00
}
2019-07-10 08:20:39 +12:00
2020-06-30 09:43:34 +12:00
$fetch = @ \file_get_contents ( $url , false );
2019-07-10 08:20:39 +12:00
2020-06-30 09:43:34 +12:00
if ( ! $fetch ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: AVATAR_IMAGE_NOT_FOUND );
2020-06-30 09:43:34 +12:00
}
2019-07-10 08:20:39 +12:00
2020-06-30 09:43:34 +12:00
try {
2021-02-20 02:59:46 +13:00
$image = new Image ( $fetch );
2022-05-09 03:10:56 +12:00
} catch ( \Exception $exception ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Unable to parse image' );
2020-06-30 09:43:34 +12:00
}
2019-07-10 08:20:39 +12:00
2021-02-20 02:59:46 +13:00
$image -> crop (( int ) $width , ( int ) $height );
2020-06-30 09:43:34 +12:00
$output = ( empty ( $output )) ? $type : $output ;
2021-02-20 02:59:46 +13:00
$data = $image -> output ( $output , $quality );
2022-07-24 21:49:51 +12:00
$response
2022-07-29 03:24:18 +12:00
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + 60 * 60 * 24 * 30 ) . ' GMT' )
2022-07-24 21:49:51 +12:00
-> setContentType ( 'image/png' )
2023-04-19 19:25:05 +12:00
-> file ( $data );
2021-02-20 02:59:46 +13:00
unset ( $image );
2020-12-27 03:59:15 +13:00
});
2019-07-10 08:20:39 +12:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/avatars/favicon' )
2019-05-09 18:54:39 +12:00
-> desc ( 'Get Favicon' )
2022-07-24 19:05:24 +12:00
-> groups ([ 'api' , 'avatars' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'avatars.read' )
2022-08-17 21:25:47 +12:00
-> label ( 'cache' , true )
2022-08-16 01:55:11 +12:00
-> label ( 'cache.resource' , 'avatar/favicon' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'avatars' )
-> label ( 'sdk.method' , 'getFavicon' )
2020-05-18 16:26:28 +12:00
-> label ( 'sdk.methodType' , 'location' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/avatars/get-favicon.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
2020-11-12 11:02:02 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_IMAGE )
2022-02-17 04:16:37 +13:00
-> param ( 'url' , '' , new URL ([ 'http' , 'https' ]), 'Website URL which you want to fetch the favicon from.' )
2020-12-27 03:59:15 +13:00
-> inject ( 'response' )
2022-07-08 02:51:22 +12:00
-> action ( function ( string $url , Response $response ) {
2020-06-30 09:43:34 +12:00
$width = 56 ;
$height = 56 ;
$quality = 80 ;
$output = 'png' ;
$type = 'png' ;
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
if ( ! \extension_loaded ( 'imagick' )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Imagick extension is missing' );
2020-06-30 09:43:34 +12:00
}
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
$curl = \curl_init ();
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
\curl_setopt_array ( $curl , [
CURLOPT_RETURNTRANSFER => 1 ,
CURLOPT_FOLLOWLOCATION => true ,
CURLOPT_MAXREDIRS => 3 ,
CURLOPT_URL => $url ,
2022-05-09 03:10:56 +12:00
CURLOPT_USERAGENT => \sprintf (
APP_USERAGENT ,
2020-06-30 23:09:28 +12:00
App :: getEnv ( '_APP_VERSION' , 'UNKNOWN' ),
2020-06-30 09:43:34 +12:00
App :: getEnv ( '_APP_SYSTEM_SECURITY_EMAIL_ADDRESS' , APP_EMAIL_SECURITY )
),
]);
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
$html = \curl_exec ( $curl );
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
\curl_close ( $curl );
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
if ( ! $html ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: AVATAR_REMOTE_URL_FAILED );
2020-06-30 09:43:34 +12:00
}
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
$doc = new DOMDocument ();
$doc -> strictErrorChecking = false ;
@ $doc -> loadHTML ( $html );
$links = $doc -> getElementsByTagName ( 'link' );
$outputHref = '' ;
$outputExt = '' ;
$space = 0 ;
foreach ( $links as $link ) { /* @var $link DOMElement */
$href = $link -> getAttribute ( 'href' );
$rel = $link -> getAttribute ( 'rel' );
$sizes = $link -> getAttribute ( 'sizes' );
$absolute = URLParse :: unparse ( \array_merge ( \parse_url ( $url ), \parse_url ( $href )));
switch ( \strtolower ( $rel )) {
case 'icon' :
case 'shortcut icon' :
//case 'apple-touch-icon':
$ext = \pathinfo ( \parse_url ( $absolute , PHP_URL_PATH ), PATHINFO_EXTENSION );
switch ( $ext ) {
case 'ico' :
case 'png' :
case 'jpg' :
case 'jpeg' :
$size = \explode ( 'x' , \strtolower ( $sizes ));
2022-11-10 00:45:15 +13:00
$sizeWidth = ( int ) ( $size [ 0 ] ? ? 0 );
$sizeHeight = ( int ) ( $size [ 1 ] ? ? 0 );
2020-06-30 09:43:34 +12:00
if (( $sizeWidth * $sizeHeight ) >= $space ) {
$space = $sizeWidth * $sizeHeight ;
$outputHref = $absolute ;
$outputExt = $ext ;
}
break ;
}
2019-07-07 07:43:45 +12:00
2020-06-30 09:43:34 +12:00
break ;
2019-05-09 18:54:39 +12:00
}
2020-06-30 09:43:34 +12:00
}
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
if ( empty ( $outputHref ) || empty ( $outputExt )) {
$default = \parse_url ( $url );
2019-05-09 18:54:39 +12:00
2021-02-20 02:59:46 +13:00
$outputHref = $default [ 'scheme' ] . '://' . $default [ 'host' ] . '/favicon.ico' ;
2020-06-30 09:43:34 +12:00
$outputExt = 'ico' ;
}
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
if ( 'ico' == $outputExt ) { // Skip crop, Imagick isn\'t supporting icon files
$data = @ \file_get_contents ( $outputHref , false );
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
if ( empty ( $data ) || ( \mb_substr ( $data , 0 , 5 ) === '<html' ) || \mb_substr ( $data , 0 , 5 ) === '<!doc' ) {
2022-08-14 18:56:12 +12:00
throw new Exception ( Exception :: AVATAR_ICON_NOT_FOUND , 'Favicon not found' );
2019-05-09 18:54:39 +12:00
}
2022-07-27 00:50:33 +12:00
$response
2022-07-31 06:55:36 +12:00
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + 60 * 60 * 24 * 30 ) . ' GMT' )
2022-07-27 00:50:33 +12:00
-> setContentType ( 'image/x-icon' )
2023-04-19 19:25:05 +12:00
-> file ( $data );
2020-06-30 09:43:34 +12:00
}
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
$fetch = @ \file_get_contents ( $outputHref , false );
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
if ( ! $fetch ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: AVATAR_ICON_NOT_FOUND );
2020-06-30 09:43:34 +12:00
}
2019-05-09 18:54:39 +12:00
2021-02-20 02:59:46 +13:00
$image = new Image ( $fetch );
$image -> crop (( int ) $width , ( int ) $height );
2020-06-30 09:43:34 +12:00
$output = ( empty ( $output )) ? $type : $output ;
2021-02-20 02:59:46 +13:00
$data = $image -> output ( $output , $quality );
2020-06-30 09:43:34 +12:00
2022-07-24 21:49:51 +12:00
$response
2022-07-29 03:24:18 +12:00
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + 60 * 60 * 24 * 30 ) . ' GMT' )
2022-07-24 21:49:51 +12:00
-> setContentType ( 'image/png' )
2023-04-19 19:25:05 +12:00
-> file ( $data );
2021-02-20 02:59:46 +13:00
unset ( $image );
2020-12-27 03:59:15 +13:00
});
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/avatars/qr' )
2019-11-28 06:24:36 +13:00
-> desc ( 'Get QR Code' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'avatars' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'avatars.read' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'avatars' )
-> label ( 'sdk.method' , 'getQR' )
2020-05-18 16:26:28 +12:00
-> label ( 'sdk.methodType' , 'location' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/avatars/get-qr.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
2020-11-12 11:02:02 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_IMAGE_PNG )
2020-09-11 02:40:14 +12:00
-> param ( 'text' , '' , new Text ( 512 ), 'Plain text to be converted to QR code image.' )
2022-04-12 23:36:03 +12:00
-> param ( 'size' , 400 , new Range ( 1 , 1000 ), 'QR code size. Pass an integer between 1 to 1000. Defaults to 400.' , true )
2020-09-11 02:40:14 +12:00
-> param ( 'margin' , 1 , new Range ( 0 , 10 ), 'Margin from edge. Pass an integer between 0 to 10. Defaults to 1.' , true )
-> param ( 'download' , false , new Boolean ( true ), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.' , true )
2020-12-27 03:59:15 +13:00
-> inject ( 'response' )
2022-05-09 03:10:56 +12:00
-> action ( function ( string $text , int $size , int $margin , bool $download , Response $response ) {
2020-06-21 23:56:42 +12:00
2020-06-30 09:43:34 +12:00
$download = ( $download === '1' || $download === 'true' || $download === 1 || $download === true );
2020-10-27 13:12:35 +13:00
$options = new QROptions ([
2021-01-10 13:07:58 +13:00
'addQuietzone' => true ,
'quietzoneSize' => $margin ,
'outputType' => QRCode :: OUTPUT_IMAGICK ,
2020-10-23 07:50:57 +13:00
]);
2020-10-27 13:12:35 +13:00
$qrcode = new QRCode ( $options );
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
if ( $download ) {
$response -> addHeader ( 'Content-Disposition' , 'attachment; filename="qr.png"' );
2020-06-10 07:48:26 +12:00
}
2020-06-30 09:43:34 +12:00
2021-02-20 02:59:46 +13:00
$image = new Image ( $qrcode -> render ( $text ));
$image -> crop (( int ) $size , ( int ) $size );
2021-01-10 13:17:44 +13:00
2020-06-30 09:43:34 +12:00
$response
2022-07-27 00:50:33 +12:00
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + ( 60 * 60 * 24 * 45 )) . ' GMT' ) // 45 days cache
2020-06-30 09:43:34 +12:00
-> setContentType ( 'image/png' )
2023-04-19 19:25:05 +12:00
-> send ( $image -> output ( 'png' , 9 ));
2020-12-27 03:59:15 +13:00
});
2020-06-10 07:48:26 +12:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/avatars/initials' )
2020-06-10 07:48:26 +12:00
-> desc ( 'Get User Initials' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'avatars' ])
2020-06-10 07:48:26 +12:00
-> label ( 'scope' , 'avatars.read' )
2022-08-16 01:55:11 +12:00
-> label ( 'cache.resource' , 'avatar/initials' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2020-06-10 07:48:26 +12:00
-> label ( 'sdk.namespace' , 'avatars' )
-> label ( 'sdk.method' , 'getInitials' )
-> label ( 'sdk.methodType' , 'location' )
-> label ( 'sdk.description' , '/docs/references/avatars/get-initials.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
2020-11-12 11:02:02 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_IMAGE_PNG )
2020-09-11 02:40:14 +12:00
-> param ( 'name' , '' , new Text ( 128 ), 'Full Name. When empty, current user name or email will be used. Max length: 128 chars.' , true )
2022-04-20 20:27:28 +12:00
-> param ( 'width' , 500 , new Range ( 0 , 2000 ), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.' , true )
-> param ( 'height' , 500 , new Range ( 0 , 2000 ), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.' , true )
2020-09-11 02:40:14 +12:00
-> param ( 'background' , '' , new HexColor (), 'Changes background color. By default a random color will be picked and stay will persistent to the given name.' , true )
2020-12-27 03:59:15 +13:00
-> inject ( 'response' )
-> inject ( 'user' )
2022-09-05 21:36:01 +12:00
-> action ( function ( string $name , int $width , int $height , string $background , Response $response , Document $user ) {
2020-06-30 09:43:34 +12:00
$themes = [
2022-09-09 23:09:04 +12:00
[ 'background' => '#FFA1CE' ], // Default (Pink)
2022-09-05 21:24:56 +12:00
[ 'background' => '#FDC584' ], // Orange
[ 'background' => '#94DBD1' ], // Green
[ 'background' => '#A1C4FF' ], // Blue
[ 'background' => '#FFA1CE' ], // Pink
[ 'background' => '#CBB1FC' ] // Purple
2020-06-30 09:43:34 +12:00
];
$name = ( ! empty ( $name )) ? $name : $user -> getAttribute ( 'name' , $user -> getAttribute ( 'email' , '' ));
$words = \explode ( ' ' , \strtoupper ( $name ));
2021-07-26 00:13:49 +12:00
// if there is no space, try to split by `_` underscore
2022-05-09 03:10:56 +12:00
$words = ( count ( $words ) == 1 ) ? \explode ( '_' , \strtoupper ( $name )) : $words ;
2020-06-30 09:43:34 +12:00
$initials = null ;
$code = 0 ;
foreach ( $words as $key => $w ) {
2020-10-15 10:34:57 +13:00
$initials .= $w [ 0 ] ? ? '' ;
2020-06-30 09:43:34 +12:00
$code += ( isset ( $w [ 0 ])) ? \ord ( $w [ 0 ]) : 0 ;
if ( $key == 1 ) {
break ;
2020-06-10 07:48:26 +12:00
}
2020-06-30 09:43:34 +12:00
}
2020-06-10 07:48:26 +12:00
2021-02-20 02:59:46 +13:00
$rand = \substr ( $code , - 1 );
2022-09-05 21:36:01 +12:00
// Wrap rand value to avoid out of range
$rand = ( $rand > \count ( $themes ) - 1 ) ? $rand % \count ( $themes ) : $rand ;
2021-02-20 02:59:46 +13:00
$background = ( ! empty ( $background )) ? '#' . $background : $themes [ $rand ][ 'background' ];
2020-06-30 09:43:34 +12:00
$image = new \Imagick ();
2022-09-05 21:24:56 +12:00
$punch = new \Imagick ();
2020-06-30 09:43:34 +12:00
$draw = new \ImagickDraw ();
$fontSize = \min ( $width , $height ) / 2 ;
2021-02-20 02:59:46 +13:00
2022-09-05 21:24:56 +12:00
$punch -> newImage ( $width , $height , 'transparent' );
2022-11-15 03:31:24 +13:00
$draw -> setFont ( __DIR__ . " /../../assets/fonts/poppins-v9-latin-500.ttf " );
$image -> setFont ( __DIR__ . " /../../assets/fonts/poppins-v9-latin-500.ttf " );
2020-06-30 09:43:34 +12:00
2022-09-05 21:24:56 +12:00
$draw -> setFillColor ( new ImagickPixel ( 'black' ));
2020-06-30 09:43:34 +12:00
$draw -> setFontSize ( $fontSize );
2021-02-20 02:59:46 +13:00
2020-06-30 09:43:34 +12:00
$draw -> setTextAlignment ( \Imagick :: ALIGN_CENTER );
$draw -> annotation ( $width / 1.97 , ( $height / 2 ) + ( $fontSize / 3 ), $initials );
2021-02-20 02:59:46 +13:00
2022-09-05 21:24:56 +12:00
$punch -> drawImage ( $draw );
$punch -> negateImage ( true , Imagick :: CHANNEL_ALPHA );
2020-06-30 09:43:34 +12:00
$image -> newImage ( $width , $height , $background );
$image -> setImageFormat ( " png " );
2022-09-05 21:24:56 +12:00
$image -> compositeImage ( $punch , Imagick :: COMPOSITE_COPYOPACITY , 0 , 0 );
2020-06-30 09:43:34 +12:00
//$image->setImageCompressionQuality(9 - round(($quality / 100) * 9));
2020-06-10 07:48:26 +12:00
2020-06-30 09:43:34 +12:00
$response
2021-02-20 02:59:46 +13:00
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + ( 60 * 60 * 24 * 45 )) . ' GMT' ) // 45 days cache
2020-06-30 09:43:34 +12:00
-> setContentType ( 'image/png' )
2023-04-19 19:25:05 +12:00
-> file ( $image -> getImageBlob ());
});
2023-04-26 23:06:11 +12:00
App :: get ( '/v1/cards/cloud' )
2023-04-26 20:21:10 +12:00
-> desc ( 'Get Front Of Cloud Card' )
2023-04-19 19:25:05 +12:00
-> groups ([ 'api' , 'avatars' ])
-> label ( 'scope' , 'avatars.read' )
2023-04-29 08:03:44 +12:00
-> label ( 'cache' , true )
-> label ( 'cache.resourceType' , 'cards/cloud' )
-> label ( 'cache.resource' , 'card/{request.userId}' )
2023-04-19 19:25:05 +12:00
-> label ( 'docs' , false )
-> label ( 'origin' , '*' )
2023-04-26 20:21:10 +12:00
-> param ( 'userId' , '' , new UID (), 'User ID.' , true )
2023-04-28 00:34:50 +12:00
-> param ( 'mock' , '' , new WhiteList ([ 'employee' , 'employee-2digit' , 'hero' , 'contributor' , 'normal' , 'platinum' , 'normal-no-github' , 'normal-long' ]), 'Mocking behaviour.' , true )
2023-05-01 23:54:41 +12:00
-> param ( 'width' , 0 , new Range ( 0 , 512 ), 'Resize image width, Pass an integer between 0 to 512.' , true )
-> param ( 'height' , 0 , new Range ( 0 , 320 ), 'Resize image height, Pass an integer between 0 to 320.' , true )
2023-04-19 19:25:05 +12:00
-> inject ( 'user' )
-> inject ( 'project' )
-> inject ( 'dbForProject' )
2023-04-26 20:21:10 +12:00
-> inject ( 'dbForConsole' )
2023-04-19 19:25:05 +12:00
-> inject ( 'response' )
2023-04-26 20:21:10 +12:00
-> inject ( 'heroes' )
-> inject ( 'contributors' )
-> inject ( 'employees' )
2023-04-29 23:33:38 +12:00
-> inject ( 'logger' )
-> action ( function ( string $userId , string $mock , int $width , int $height , Document $user , Document $project , Database $dbForProject , Database $dbForConsole , Response $response , array $heroes , array $contributors , array $employees , ? Logger $logger ) use ( $getUserGitHub ) {
2023-04-26 21:10:06 +12:00
$user = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'users' , $userId ));
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
if ( $user -> isEmpty () && empty ( $mock )) {
2023-04-26 21:10:06 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2023-04-26 20:21:10 +12:00
}
2023-04-19 19:25:05 +12:00
2023-04-26 23:51:19 +12:00
if ( ! $mock ) {
2023-04-26 20:21:10 +12:00
$name = $user -> getAttribute ( 'name' , 'Anonymous' );
$email = $user -> getAttribute ( 'email' , '' );
$createdAt = new \DateTime ( $user -> getCreatedAt ());
2023-04-26 23:51:19 +12:00
2023-04-29 23:33:38 +12:00
$gitHub = $getUserGitHub ( $user -> getId (), $project , $dbForProject , $dbForConsole , $logger );
2023-04-26 20:21:10 +12:00
$githubName = $gitHub [ 'name' ] ? ? '' ;
$githubId = $gitHub [ 'id' ] ? ? '' ;
2023-04-26 23:51:19 +12:00
2023-04-27 20:24:53 +12:00
$isHero = \array_key_exists ( $email , $heroes );
2023-04-26 20:21:10 +12:00
$isContributor = \in_array ( $githubId , $contributors );
2023-04-27 20:24:53 +12:00
$isEmployee = \array_key_exists ( $email , $employees );
$employeeNumber = $isEmployee ? $employees [ $email ][ 'spot' ] : '' ;
if ( $isHero ) {
$createdAt = new \DateTime ( $heroes [ $email ][ 'memberSince' ] ? ? '' );
2023-04-29 08:04:27 +12:00
} elseif ( $isEmployee ) {
2023-04-27 20:24:53 +12:00
$createdAt = new \DateTime ( $employees [ $email ][ 'memberSince' ] ? ? '' );
}
2023-04-28 19:30:30 +12:00
if ( ! $isEmployee && ! empty ( $githubName )) {
2023-04-27 20:24:53 +12:00
$employeeGitHub = \array_search ( \strtolower ( $githubName ), \array_map ( fn ( $employee ) => \strtolower ( $employee [ 'gitHub' ]) ? ? '' , $employees ));
if ( ! empty ( $employeeGitHub )) {
$isEmployee = true ;
$employeeNumber = $isEmployee ? $employees [ $employeeGitHub ][ 'spot' ] : '' ;
$createdAt = new \DateTime ( $employees [ $employeeGitHub ][ 'memberSince' ] ? ? '' );
}
}
2023-04-26 23:51:19 +12:00
2023-04-26 23:06:11 +12:00
$isPlatinum = $user -> getInternalId () % 100 === 0 ;
2023-04-26 20:21:10 +12:00
} else {
$name = $mock === 'normal-long' ? 'Sir First Walter O\'Brian Junior' : 'Walter O\'Brian' ;
$createdAt = new \DateTime ( 'now' );
$githubName = $mock === 'normal-no-github' ? '' : ( $mock === 'normal-long' ? 'sir-first-walterobrian-junior' : 'walterobrian' );
$isHero = $mock === 'hero' ;
$isContributor = $mock === 'contributor' ;
$isEmployee = \str_starts_with ( $mock , 'employee' );
$employeeNumber = match ( $mock ) {
'employee' => '1' ,
'employee-2digit' => '18' ,
default => ''
};
$isPlatinum = $mock === 'platinum' ;
}
2023-04-19 19:25:05 +12:00
2023-04-27 20:24:53 +12:00
if ( $isEmployee ) {
$isContributor = false ;
$isHero = false ;
}
if ( $isHero ) {
$isContributor = false ;
$isEmployee = false ;
}
if ( $isContributor ) {
$isHero = false ;
$isEmployee = false ;
}
2023-04-26 20:21:10 +12:00
$isGolden = $isEmployee || $isHero || $isContributor ;
$isPlatinum = $isGolden ? false : $isPlatinum ;
$memberSince = \strtoupper ( 'Member since ' . $createdAt -> format ( 'M' ) . ' ' . $createdAt -> format ( 'd' ) . ', ' . $createdAt -> format ( 'o' ));
$imagePath = $isGolden ? 'front-golden.png' : ( $isPlatinum ? 'front-platinum.png' : 'front.png' );
2023-04-29 20:40:22 +12:00
$baseImage = new \Imagick ( __DIR__ . '/../../../public/images/cards/cloud/' . $imagePath );
2023-04-26 20:21:10 +12:00
2023-04-26 23:51:19 +12:00
if ( $isEmployee ) {
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/employee.png' );
2023-04-26 20:21:10 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
2023-05-01 23:54:41 +12:00
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 793 , 35 );
2023-04-26 20:21:10 +12:00
$text = new \ImagickDraw ();
$text -> setTextAlignment ( Imagick :: ALIGN_CENTER );
2023-04-29 20:40:22 +12:00
$text -> setFont ( __DIR__ . '/../../../public/fonts/Inter-Bold.ttf' );
2023-04-26 20:21:10 +12:00
$text -> setFillColor ( new \ImagickPixel ( '#FFFADF' ));
2023-05-01 23:54:41 +12:00
$text -> setFontSize ( \strlen ( $employeeNumber ) <= 2 ? 54 : 48 );
2023-04-26 20:21:10 +12:00
$text -> setFontWeight ( 700 );
$metricsText = $baseImage -> queryFontMetrics ( $text , $employeeNumber );
$hashtag = new \ImagickDraw ();
$hashtag -> setTextAlignment ( Imagick :: ALIGN_CENTER );
2023-04-29 20:40:22 +12:00
$hashtag -> setFont ( __DIR__ . '/../../../public/fonts/Inter-Bold.ttf' );
2023-04-26 20:21:10 +12:00
$hashtag -> setFillColor ( new \ImagickPixel ( '#FFFADF' ));
2023-05-01 23:54:41 +12:00
$hashtag -> setFontSize ( 28 );
2023-04-26 20:21:10 +12:00
$hashtag -> setFontWeight ( 700 );
$metricsHashtag = $baseImage -> queryFontMetrics ( $hashtag , '#' );
2023-05-01 23:54:41 +12:00
$startX = 898 ;
$totalWidth = $metricsHashtag [ 'textWidth' ] + 12 + $metricsText [ 'textWidth' ];
2023-04-26 20:21:10 +12:00
2023-04-26 23:51:19 +12:00
$hashtagX = ( $metricsHashtag [ 'textWidth' ] / 2 );
2023-05-01 23:54:41 +12:00
$textX = $hashtagX + 12 + ( $metricsText [ 'textWidth' ] / 2 );
2023-04-26 23:51:19 +12:00
$hashtagX -= $totalWidth / 2 ;
$textX -= $totalWidth / 2 ;
2023-04-26 20:21:10 +12:00
$hashtagX += $startX ;
$textX += $startX ;
2023-05-01 23:54:41 +12:00
$baseImage -> annotateImage ( $hashtag , $hashtagX , 150 , 0 , '#' );
$baseImage -> annotateImage ( $text , $textX , 150 , 0 , $employeeNumber );
2023-04-26 20:21:10 +12:00
}
2023-04-19 19:25:05 +12:00
2023-04-26 23:51:19 +12:00
if ( $isContributor ) {
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/contributor.png' );
2023-04-26 20:21:10 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
2023-05-01 23:54:41 +12:00
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 793 , 34 );
2023-04-26 20:21:10 +12:00
}
2023-04-19 19:25:05 +12:00
2023-04-26 23:51:19 +12:00
if ( $isHero ) {
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/hero.png' );
2023-04-26 20:21:10 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
2023-05-01 23:54:41 +12:00
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 793 , 34 );
2023-04-26 20:21:10 +12:00
}
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
setlocale ( LC_ALL , " en_US.utf8 " );
2023-05-02 20:28:14 +12:00
// $name = \iconv("utf-8", "ascii//TRANSLIT", $name);
// $memberSince = \iconv("utf-8", "ascii//TRANSLIT", $memberSince);
// $githubName = \iconv("utf-8", "ascii//TRANSLIT", $githubName);
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
$text = new \ImagickDraw ();
$text -> setTextAlignment ( Imagick :: ALIGN_CENTER );
2023-04-29 20:40:22 +12:00
$text -> setFont ( __DIR__ . '/../../../public/fonts/Poppins-Bold.ttf' );
2023-04-26 20:21:10 +12:00
$text -> setFillColor ( new \ImagickPixel ( '#FFFFFF' ));
2023-04-19 19:25:05 +12:00
2023-05-02 20:28:14 +12:00
if ( \strlen ( $name ) > 32 ) {
$name = \substr ( $name , 0 , 32 );
2023-04-26 20:21:10 +12:00
}
2023-04-19 19:25:05 +12:00
2023-04-26 23:51:19 +12:00
if ( \strlen ( $name ) <= 23 ) {
2023-05-01 23:54:41 +12:00
$text -> setFontSize ( 80 );
2023-04-29 05:46:24 +12:00
$scalingDown = false ;
2023-04-26 20:21:10 +12:00
} else {
2023-05-01 23:54:41 +12:00
$text -> setFontSize ( 54 );
2023-04-29 05:46:24 +12:00
$scalingDown = true ;
2023-04-26 20:21:10 +12:00
}
$text -> setFontWeight ( 700 );
2023-05-01 23:54:41 +12:00
$baseImage -> annotateImage ( $text , 512 , 477 , 0 , $name );
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
$text = new \ImagickDraw ();
$text -> setTextAlignment ( Imagick :: ALIGN_CENTER );
2023-04-29 20:40:22 +12:00
$text -> setFont ( __DIR__ . '/../../../public/fonts/Inter-SemiBold.ttf' );
2023-04-26 20:21:10 +12:00
$text -> setFillColor ( new \ImagickPixel ( $isGolden || $isPlatinum ? '#FFFFFF' : '#FFB9CC' ));
2023-05-01 23:54:41 +12:00
$text -> setFontSize ( 27 );
2023-04-26 20:21:10 +12:00
$text -> setFontWeight ( 600 );
2023-04-28 00:34:50 +12:00
$text -> setTextKerning ( 1.08 );
2023-05-01 23:54:41 +12:00
$baseImage -> annotateImage ( $text , 512 , 541 , 0 , \strtoupper ( $memberSince ));
2023-04-26 20:21:10 +12:00
if ( ! empty ( $githubName )) {
$text = new \ImagickDraw ();
$text -> setTextAlignment ( Imagick :: ALIGN_CENTER );
2023-04-29 20:40:22 +12:00
$text -> setFont ( __DIR__ . '/../../../public/fonts/Inter-Regular.ttf' );
2023-04-26 20:21:10 +12:00
$text -> setFillColor ( new \ImagickPixel ( '#FFFFFF' ));
2023-05-01 23:54:41 +12:00
$text -> setFontSize ( $scalingDown ? 28 : 32 );
2023-04-26 20:21:10 +12:00
$text -> setFontWeight ( 400 );
$metrics = $baseImage -> queryFontMetrics ( $text , $githubName );
2023-05-01 23:54:41 +12:00
$baseImage -> annotateImage ( $text , 512 + 20 + 4 , 373 + ( $scalingDown ? 2 : 0 ), 0 , $githubName );
2023-04-26 20:21:10 +12:00
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/github.png' );
2023-04-26 20:21:10 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
2023-05-01 23:54:41 +12:00
$precisionFix = 5 ;
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 512 - ( $metrics [ 'textWidth' ] / 2 ) - 20 - 4 , 373 - ( $metrics [ 'textHeight' ] - $precisionFix ));
2023-04-26 20:21:10 +12:00
}
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
if ( ! empty ( $width ) || ! empty ( $height )) {
$baseImage -> resizeImage ( $width , $height , Imagick :: FILTER_LANCZOS , 1 );
}
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
$response
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + ( 60 * 60 * 24 * 45 )) . ' GMT' ) // 45 days cache
-> setContentType ( 'image/png' )
-> file ( $baseImage -> getImageBlob ());
});
2023-04-19 19:25:05 +12:00
2023-04-26 23:06:11 +12:00
App :: get ( '/v1/cards/cloud-back' )
2023-04-26 20:21:10 +12:00
-> desc ( 'Get Back Of Cloud Card' )
-> groups ([ 'api' , 'avatars' ])
-> label ( 'scope' , 'avatars.read' )
2023-04-29 08:03:44 +12:00
-> label ( 'cache' , true )
-> label ( 'cache.resourceType' , 'cards/cloud-back' )
-> label ( 'cache.resource' , 'card-back/{request.userId}' )
2023-04-26 20:21:10 +12:00
-> label ( 'docs' , false )
-> label ( 'origin' , '*' )
-> param ( 'userId' , '' , new UID (), 'User ID.' , true )
-> param ( 'mock' , '' , new WhiteList ([ 'golden' , 'normal' , 'platinum' ]), 'Mocking behaviour.' , true )
2023-05-01 23:54:41 +12:00
-> param ( 'width' , 0 , new Range ( 0 , 512 ), 'Resize image width, Pass an integer between 0 to 512.' , true )
-> param ( 'height' , 0 , new Range ( 0 , 320 ), 'Resize image height, Pass an integer between 0 to 320.' , true )
2023-04-26 20:21:10 +12:00
-> inject ( 'user' )
-> inject ( 'project' )
-> inject ( 'dbForProject' )
-> inject ( 'dbForConsole' )
-> inject ( 'response' )
-> inject ( 'heroes' )
-> inject ( 'contributors' )
-> inject ( 'employees' )
2023-04-29 23:33:38 +12:00
-> inject ( 'logger' )
-> action ( function ( string $userId , string $mock , int $width , int $height , Document $user , Document $project , Database $dbForProject , Database $dbForConsole , Response $response , array $heroes , array $contributors , array $employees , ? Logger $logger ) use ( $getUserGitHub ) {
2023-04-26 21:10:06 +12:00
$user = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'users' , $userId ));
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
if ( $user -> isEmpty () && empty ( $mock )) {
2023-04-26 21:10:06 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2023-04-26 20:21:10 +12:00
}
2023-04-25 19:35:48 +12:00
2023-04-26 23:51:19 +12:00
if ( ! $mock ) {
2023-04-26 20:21:10 +12:00
$userId = $user -> getId ();
$email = $user -> getAttribute ( 'email' , '' );
2023-04-26 23:51:19 +12:00
2023-04-29 23:33:38 +12:00
$gitHub = $getUserGitHub ( $user -> getId (), $project , $dbForProject , $dbForConsole , $logger );
2023-04-26 20:21:10 +12:00
$githubId = $gitHub [ 'id' ] ? ? '' ;
2023-04-26 23:51:19 +12:00
2023-04-27 20:24:53 +12:00
$isHero = \array_key_exists ( $email , $heroes );
2023-04-26 20:21:10 +12:00
$isContributor = \in_array ( $githubId , $contributors );
2023-04-27 20:24:53 +12:00
$isEmployee = \array_key_exists ( $email , $employees );
2023-04-26 20:21:10 +12:00
$isGolden = $isEmployee || $isHero || $isContributor ;
2023-04-26 23:06:11 +12:00
$isPlatinum = $user -> getInternalId () % 100 === 0 ;
2023-04-26 20:21:10 +12:00
} else {
$userId = '63e0bcf3c3eb803ba530' ;
$isGolden = $mock === 'golden' ;
$isPlatinum = $mock === 'platinum' ;
}
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
$userId = 'UID ' . $userId ;
2023-04-25 19:35:48 +12:00
2023-04-26 20:21:10 +12:00
$isPlatinum = $isGolden ? false : $isPlatinum ;
2023-04-25 19:35:48 +12:00
2023-04-26 20:21:10 +12:00
$imagePath = $isGolden ? 'back-golden.png' : ( $isPlatinum ? 'back-platinum.png' : 'back.png' );
2023-04-25 19:35:48 +12:00
2023-04-29 20:40:22 +12:00
$baseImage = new \Imagick ( __DIR__ . '/../../../public/images/cards/cloud/' . $imagePath );
2023-04-25 19:35:48 +12:00
2023-04-26 20:21:10 +12:00
setlocale ( LC_ALL , " en_US.utf8 " );
2023-05-02 20:28:14 +12:00
// $userId = \iconv("utf-8", "ascii//TRANSLIT", $userId);
2023-04-19 19:25:05 +12:00
2023-04-26 20:21:10 +12:00
$text = new \ImagickDraw ();
$text -> setTextAlignment ( Imagick :: ALIGN_CENTER );
2023-04-29 20:40:22 +12:00
$text -> setFont ( __DIR__ . '/../../../public/fonts/SourceCodePro-Regular.ttf' );
2023-04-26 20:21:10 +12:00
$text -> setFillColor ( new \ImagickPixel ( $isGolden ? '#664A1E' : ( $isPlatinum ? '#555555' : '#E8E9F0' )));
2023-05-01 23:54:41 +12:00
$text -> setFontSize ( 28 );
2023-04-26 20:21:10 +12:00
$text -> setFontWeight ( 400 );
2023-05-01 23:54:41 +12:00
$baseImage -> annotateImage ( $text , 512 , 596 , 0 , $userId );
2023-04-19 19:25:05 +12:00
if ( ! empty ( $width ) || ! empty ( $height )) {
$baseImage -> resizeImage ( $width , $height , Imagick :: FILTER_LANCZOS , 1 );
}
$response
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + ( 60 * 60 * 24 * 45 )) . ' GMT' ) // 45 days cache
-> setContentType ( 'image/png' )
-> file ( $baseImage -> getImageBlob ());
2020-12-27 03:59:15 +13:00
});
2023-04-26 20:21:10 +12:00
2023-04-26 23:06:11 +12:00
App :: get ( '/v1/cards/cloud-og' )
-> desc ( 'Get OG Image From Cloud Card' )
-> groups ([ 'api' , 'avatars' ])
-> label ( 'scope' , 'avatars.read' )
2023-04-29 08:03:44 +12:00
-> label ( 'cache' , true )
-> label ( 'cache.resourceType' , 'cards/cloud-og' )
-> label ( 'cache.resource' , 'card-og/{request.userId}' )
2023-04-26 23:06:11 +12:00
-> label ( 'docs' , false )
-> label ( 'origin' , '*' )
-> param ( 'userId' , '' , new UID (), 'User ID.' , true )
2023-04-29 05:46:24 +12:00
-> param ( 'mock' , '' , new WhiteList ([ 'employee' , 'employee-2digit' , 'hero' , 'contributor' , 'normal' , 'platinum' , 'normal-no-github' , 'normal-long' , 'normal-long-right' , 'normal-long-middle' , 'normal-bg2' , 'normal-bg3' , 'normal-right' , 'normal-middle' , 'platinum-right' , 'platinum-middle' , 'hero-middle' , 'hero-right' , 'contributor-right' , 'employee-right' , 'contributor-middle' , 'employee-middle' , 'employee-2digit-middle' , 'employee-2digit-right' ]), 'Mocking behaviour.' , true )
2023-04-26 23:06:11 +12:00
-> param ( 'width' , 0 , new Range ( 0 , 1024 ), 'Resize image card width, Pass an integer between 0 to 1024.' , true )
-> param ( 'height' , 0 , new Range ( 0 , 1024 ), 'Resize image card height, Pass an integer between 0 to 1024.' , true )
-> inject ( 'user' )
-> inject ( 'project' )
-> inject ( 'dbForProject' )
-> inject ( 'dbForConsole' )
-> inject ( 'response' )
-> inject ( 'heroes' )
-> inject ( 'contributors' )
-> inject ( 'employees' )
2023-04-29 23:33:38 +12:00
-> inject ( 'logger' )
-> action ( function ( string $userId , string $mock , int $width , int $height , Document $user , Document $project , Database $dbForProject , Database $dbForConsole , Response $response , array $heroes , array $contributors , array $employees , ? Logger $logger ) use ( $getUserGitHub ) {
2023-04-26 23:06:11 +12:00
$user = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'users' , $userId ));
if ( $user -> isEmpty () && empty ( $mock )) {
throw new Exception ( Exception :: USER_NOT_FOUND );
}
2023-04-26 23:51:19 +12:00
if ( ! $mock ) {
2023-04-26 23:06:11 +12:00
$internalId = $user -> getInternalId ();
$bgVariation = $internalId % 3 === 0 ? '1' : ( $internalId % 3 === 1 ? '2' : '3' );
2023-04-29 05:46:24 +12:00
$cardVariation = $internalId % 3 === 0 ? '1' : ( $internalId % 3 === 1 ? '2' : '3' );
2023-04-26 23:06:11 +12:00
$name = $user -> getAttribute ( 'name' , 'Anonymous' );
$email = $user -> getAttribute ( 'email' , '' );
$createdAt = new \DateTime ( $user -> getCreatedAt ());
2023-04-26 23:51:19 +12:00
2023-04-29 23:33:38 +12:00
$gitHub = $getUserGitHub ( $user -> getId (), $project , $dbForProject , $dbForConsole , $logger );
2023-04-26 23:06:11 +12:00
$githubName = $gitHub [ 'name' ] ? ? '' ;
$githubId = $gitHub [ 'id' ] ? ? '' ;
2023-04-26 23:51:19 +12:00
2023-04-27 20:24:53 +12:00
$isHero = \array_key_exists ( $email , $heroes );
2023-04-26 23:06:11 +12:00
$isContributor = \in_array ( $githubId , $contributors );
2023-04-27 20:24:53 +12:00
$isEmployee = \array_key_exists ( $email , $employees );
$employeeNumber = $isEmployee ? $employees [ $email ][ 'spot' ] : '' ;
if ( $isHero ) {
$createdAt = new \DateTime ( $heroes [ $email ][ 'memberSince' ] ? ? '' );
2023-04-29 08:04:27 +12:00
} elseif ( $isEmployee ) {
2023-04-27 20:24:53 +12:00
$createdAt = new \DateTime ( $employees [ $email ][ 'memberSince' ] ? ? '' );
}
2023-04-28 19:30:30 +12:00
if ( ! $isEmployee && ! empty ( $githubName )) {
2023-04-27 20:24:53 +12:00
$employeeGitHub = \array_search ( \strtolower ( $githubName ), \array_map ( fn ( $employee ) => \strtolower ( $employee [ 'gitHub' ]) ? ? '' , $employees ));
if ( ! empty ( $employeeGitHub )) {
$isEmployee = true ;
$employeeNumber = $isEmployee ? $employees [ $employeeGitHub ][ 'spot' ] : '' ;
$createdAt = new \DateTime ( $employees [ $employeeGitHub ][ 'memberSince' ] ? ? '' );
}
}
2023-04-26 23:51:19 +12:00
2023-04-26 23:06:11 +12:00
$isPlatinum = $user -> getInternalId () % 100 === 0 ;
} else {
2023-04-26 23:51:19 +12:00
$bgVariation = \str_ends_with ( $mock , '-bg2' ) ? '2' : ( \str_ends_with ( $mock , '-bg3' ) ? '3' : '1' );
2023-04-29 05:46:24 +12:00
$cardVariation = \str_ends_with ( $mock , '-right' ) ? '2' : ( \str_ends_with ( $mock , '-middle' ) ? '3' : '1' );
2023-04-28 00:34:50 +12:00
$name = \str_starts_with ( $mock , 'normal-long' ) ? 'Sir First Walter O\'Brian Junior' : 'Walter O\'Brian' ;
2023-04-26 23:06:11 +12:00
$createdAt = new \DateTime ( 'now' );
2023-04-28 00:34:50 +12:00
$githubName = $mock === 'normal-no-github' ? '' : ( \str_starts_with ( $mock , 'normal-long' ) ? 'sir-first-walterobrian-junior' : 'walterobrian' );
2023-04-27 20:24:53 +12:00
$isHero = \str_starts_with ( $mock , 'hero' );
$isContributor = \str_starts_with ( $mock , 'contributor' );
2023-04-26 23:06:11 +12:00
$isEmployee = \str_starts_with ( $mock , 'employee' );
$employeeNumber = match ( $mock ) {
'employee' => '1' ,
2023-04-27 20:24:53 +12:00
'employee-right' => '1' ,
2023-04-29 05:46:24 +12:00
'employee-middle' => '1' ,
2023-04-26 23:06:11 +12:00
'employee-2digit' => '18' ,
2023-04-28 00:34:50 +12:00
'employee-2digit-right' => '18' ,
2023-04-29 05:46:24 +12:00
'employee-2digit-middle' => '18' ,
2023-04-26 23:06:11 +12:00
default => ''
};
2023-04-28 00:34:50 +12:00
$isPlatinum = \str_starts_with ( $mock , 'platinum' );
2023-04-26 23:06:11 +12:00
}
2023-04-27 20:24:53 +12:00
if ( $isEmployee ) {
$isContributor = false ;
$isHero = false ;
}
if ( $isHero ) {
$isContributor = false ;
$isEmployee = false ;
}
if ( $isContributor ) {
$isHero = false ;
$isEmployee = false ;
}
2023-04-26 23:06:11 +12:00
$isGolden = $isEmployee || $isHero || $isContributor ;
$isPlatinum = $isGolden ? false : $isPlatinum ;
$memberSince = \strtoupper ( 'Member since ' . $createdAt -> format ( 'M' ) . ' ' . $createdAt -> format ( 'd' ) . ', ' . $createdAt -> format ( 'o' ));
2023-04-29 20:50:04 +12:00
$baseImage = new \Imagick ( __DIR__ . " /../../../public/images/cards/cloud/og-background { $bgVariation } .png " );
2023-04-26 23:39:50 +12:00
2023-04-26 23:06:11 +12:00
$cardType = $isGolden ? '-golden' : ( $isPlatinum ? '-platinum' : '' );
2023-04-26 23:39:50 +12:00
2023-04-29 20:50:04 +12:00
$image = new Imagick ( __DIR__ . " /../../../public/images/cards/cloud/og-card { $cardType } { $cardVariation } .png " );
2023-04-26 23:51:19 +12:00
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 1008 / 2 - $image -> getImageWidth () / 2 , 1008 / 2 - $image -> getImageHeight () / 2 );
2023-04-26 23:39:50 +12:00
2023-04-29 20:40:22 +12:00
$imageLogo = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/og-background-logo.png' );
2023-04-29 20:50:04 +12:00
$imageShadow = new Imagick ( __DIR__ . " /../../../public/images/cards/cloud/og-shadow { $cardType } .png " );
2023-04-26 23:51:19 +12:00
if ( $cardVariation === '1' ) {
2023-04-29 05:46:24 +12:00
$baseImage -> compositeImage ( $imageLogo , Imagick :: COMPOSITE_OVER , 32 , 1008 - $imageLogo -> getImageHeight () - 32 );
$baseImage -> compositeImage ( $imageShadow , Imagick :: COMPOSITE_OVER , - 450 , 700 );
2023-04-29 08:04:27 +12:00
} elseif ( $cardVariation === '2' ) {
2023-04-29 05:46:24 +12:00
$baseImage -> compositeImage ( $imageLogo , Imagick :: COMPOSITE_OVER , 1008 - $imageLogo -> getImageWidth () - 32 , 1008 - $imageLogo -> getImageHeight () - 32 );
$baseImage -> compositeImage ( $imageShadow , Imagick :: COMPOSITE_OVER , - 20 , 710 );
2023-04-26 23:39:50 +12:00
} else {
2023-04-29 05:46:24 +12:00
$baseImage -> compositeImage ( $imageLogo , Imagick :: COMPOSITE_OVER , 1008 - $imageLogo -> getImageWidth () - 32 , 1008 - $imageLogo -> getImageHeight () - 32 );
$baseImage -> compositeImage ( $imageShadow , Imagick :: COMPOSITE_OVER , - 135 , 710 );
2023-04-26 23:39:50 +12:00
}
2023-04-26 23:06:11 +12:00
2023-04-27 20:24:53 +12:00
if ( $isEmployee ) {
2023-04-29 05:46:24 +12:00
$file = $cardVariation === '3' ? 'employee-skew.png' : 'employee.png' ;
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/' . $file );
2023-04-27 20:24:53 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
$hashtag = new \ImagickDraw ();
$hashtag -> setTextAlignment ( Imagick :: ALIGN_LEFT );
2023-04-29 20:40:22 +12:00
$hashtag -> setFont ( __DIR__ . '/../../../public/fonts/Inter-Bold.ttf' );
2023-04-27 20:24:53 +12:00
$hashtag -> setFillColor ( new \ImagickPixel ( '#FFFADF' ));
$hashtag -> setFontSize ( 20 );
$hashtag -> setFontWeight ( 700 );
$text = new \ImagickDraw ();
$text -> setTextAlignment ( Imagick :: ALIGN_LEFT );
2023-04-29 20:40:22 +12:00
$text -> setFont ( __DIR__ . '/../../../public/fonts/Inter-Bold.ttf' );
2023-04-27 20:24:53 +12:00
$text -> setFillColor ( new \ImagickPixel ( '#FFFADF' ));
$text -> setFontSize ( \strlen ( $employeeNumber ) <= 1 ? 36 : 28 );
$text -> setFontWeight ( 700 );
2023-04-29 05:46:24 +12:00
if ( $cardVariation === '3' ) {
2023-05-02 02:45:39 +12:00
$hashtag -> setFontSize ( 16 );
$text -> setFontSize ( \strlen ( $employeeNumber ) <= 1 ? 30 : 26 );
2023-04-29 05:46:24 +12:00
$hashtag -> skewY ( 20 );
$hashtag -> skewX ( 20 );
$text -> skewY ( 20 );
$text -> skewX ( 20 );
}
$metricsHashtag = $baseImage -> queryFontMetrics ( $hashtag , '#' );
2023-04-27 20:24:53 +12:00
$metricsText = $baseImage -> queryFontMetrics ( $text , $employeeNumber );
$group = new Imagick ();
$groupWidth = $metricsHashtag [ 'textWidth' ] + 6 + $metricsText [ 'textWidth' ];
if ( $cardVariation === '1' ) {
2023-04-29 05:46:24 +12:00
$group -> newImage ( $groupWidth , $metricsText [ 'textHeight' ], '#00000000' );
$group -> annotateImage ( $hashtag , 0 , $metricsText [ 'textHeight' ], 0 , '#' );
$group -> annotateImage ( $text , $metricsHashtag [ 'textWidth' ] + 6 , $metricsText [ 'textHeight' ], 0 , $employeeNumber );
$image -> resizeImage ( 120 , 120 , Imagick :: FILTER_LANCZOS , 1 );
$image -> rotateImage ( new ImagickPixel ( '#00000000' ), - 20 );
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 612 , 203 );
2023-04-27 20:24:53 +12:00
$group -> rotateImage ( new ImagickPixel ( '#00000000' ), - 22 );
2023-04-28 19:30:30 +12:00
if ( \strlen ( $employeeNumber ) <= 1 ) {
2023-04-27 20:24:53 +12:00
$baseImage -> compositeImage ( $group , Imagick :: COMPOSITE_OVER , 660 , 245 );
} else {
$baseImage -> compositeImage ( $group , Imagick :: COMPOSITE_OVER , 655 , 247 );
}
2023-04-29 08:04:27 +12:00
} elseif ( $cardVariation === '2' ) {
2023-04-29 05:46:24 +12:00
$group -> newImage ( $groupWidth , $metricsText [ 'textHeight' ], '#00000000' );
$group -> annotateImage ( $hashtag , 0 , $metricsText [ 'textHeight' ], 0 , '#' );
$group -> annotateImage ( $text , $metricsHashtag [ 'textWidth' ] + 6 , $metricsText [ 'textHeight' ], 0 , $employeeNumber );
$image -> resizeImage ( 120 , 120 , Imagick :: FILTER_LANCZOS , 1 );
$image -> rotateImage ( new ImagickPixel ( '#00000000' ), 30 );
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 715 , 425 );
2023-04-27 20:24:53 +12:00
$group -> rotateImage ( new ImagickPixel ( '#00000000' ), 32 );
2023-04-28 19:30:30 +12:00
if ( \strlen ( $employeeNumber ) <= 1 ) {
2023-04-27 20:24:53 +12:00
$baseImage -> compositeImage ( $group , Imagick :: COMPOSITE_OVER , 775 , 465 );
} else {
$baseImage -> compositeImage ( $group , Imagick :: COMPOSITE_OVER , 767 , 470 );
}
2023-04-29 05:46:24 +12:00
} else {
$group -> newImage ( 300 , 300 , '#00000000' );
$hashtag -> annotation ( 0 , $metricsText [ 'textHeight' ], '#' );
2023-05-02 02:45:39 +12:00
$text -> annotation ( $metricsHashtag [ 'textWidth' ] + 2 , $metricsText [ 'textHeight' ], $employeeNumber );
2023-04-29 05:46:24 +12:00
$group -> drawImage ( $hashtag );
$group -> drawImage ( $text );
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 640 , 293 );
if ( \strlen ( $employeeNumber ) <= 1 ) {
2023-05-02 02:45:39 +12:00
$baseImage -> compositeImage ( $group , Imagick :: COMPOSITE_OVER , 670 , 317 );
2023-04-29 05:46:24 +12:00
} else {
2023-05-02 02:45:39 +12:00
$baseImage -> compositeImage ( $group , Imagick :: COMPOSITE_OVER , 663 , 322 );
2023-04-29 05:46:24 +12:00
}
2023-04-27 20:24:53 +12:00
}
}
if ( $isContributor ) {
2023-04-29 05:46:24 +12:00
$file = $cardVariation === '3' ? 'contributor-skew.png' : 'contributor.png' ;
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/' . $file );
2023-04-27 20:24:53 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
2023-04-29 05:46:24 +12:00
if ( $cardVariation === '1' ) {
$image -> resizeImage ( 120 , 120 , Imagick :: FILTER_LANCZOS , 1 );
$image -> rotateImage ( new ImagickPixel ( '#00000000' ), - 20 );
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 612 , 203 );
2023-04-29 08:04:27 +12:00
} elseif ( $cardVariation === '2' ) {
2023-04-29 05:46:24 +12:00
$image -> resizeImage ( 120 , 120 , Imagick :: FILTER_LANCZOS , 1 );
$image -> rotateImage ( new ImagickPixel ( '#00000000' ), 30 );
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 715 , 425 );
} else {
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 640 , 293 );
}
2023-04-27 20:24:53 +12:00
}
if ( $isHero ) {
2023-04-29 05:46:24 +12:00
$file = $cardVariation === '3' ? 'hero-skew.png' : 'hero.png' ;
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/' . $file );
2023-04-27 20:24:53 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
2023-04-29 05:46:24 +12:00
if ( $cardVariation === '1' ) {
$image -> resizeImage ( 120 , 120 , Imagick :: FILTER_LANCZOS , 1 );
$image -> rotateImage ( new ImagickPixel ( '#00000000' ), - 20 );
2023-04-29 23:33:38 +12:00
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 612 , 203 );
2023-04-29 08:04:27 +12:00
} elseif ( $cardVariation === '2' ) {
2023-04-29 05:46:24 +12:00
$image -> resizeImage ( 120 , 120 , Imagick :: FILTER_LANCZOS , 1 );
$image -> rotateImage ( new ImagickPixel ( '#00000000' ), 30 );
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 715 , 425 );
} else {
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 640 , 293 );
}
2023-04-27 20:24:53 +12:00
}
2023-04-26 23:06:11 +12:00
setlocale ( LC_ALL , " en_US.utf8 " );
2023-05-02 20:28:14 +12:00
// $name = \iconv("utf-8", "ascii//TRANSLIT", $name);
// $memberSince = \iconv("utf-8", "ascii//TRANSLIT", $memberSince);
// $githubName = \iconv("utf-8", "ascii//TRANSLIT", $githubName);
2023-04-26 23:06:11 +12:00
2023-04-29 05:46:24 +12:00
$textName = new \ImagickDraw ();
$textName -> setTextAlignment ( Imagick :: ALIGN_CENTER );
2023-04-29 20:40:22 +12:00
$textName -> setFont ( __DIR__ . '/../../../public/fonts/Poppins-Bold.ttf' );
2023-04-29 05:46:24 +12:00
$textName -> setFillColor ( new \ImagickPixel ( '#FFFFFF' ));
2023-04-26 23:06:11 +12:00
2023-05-02 20:28:14 +12:00
if ( \strlen ( $name ) > 32 ) {
$name = \substr ( $name , 0 , 32 );
2023-04-27 20:24:53 +12:00
}
2023-04-28 19:30:30 +12:00
if ( $cardVariation === '1' ) {
2023-04-28 00:34:50 +12:00
if ( \strlen ( $name ) <= 23 ) {
2023-04-29 05:46:24 +12:00
$scalingDown = false ;
$textName -> setFontSize ( 54 );
2023-04-28 00:34:50 +12:00
} else {
2023-04-29 05:46:24 +12:00
$scalingDown = true ;
$textName -> setFontSize ( 36 );
}
2023-04-29 08:04:27 +12:00
} elseif ( $cardVariation === '2' ) {
2023-04-29 05:46:24 +12:00
if ( \strlen ( $name ) <= 23 ) {
$scalingDown = false ;
$textName -> setFontSize ( 50 );
} else {
$scalingDown = true ;
$textName -> setFontSize ( 34 );
2023-04-28 00:34:50 +12:00
}
2023-04-27 20:24:53 +12:00
} else {
2023-04-28 00:34:50 +12:00
if ( \strlen ( $name ) <= 23 ) {
2023-04-29 05:46:24 +12:00
$scalingDown = false ;
$textName -> setFontSize ( 44 );
2023-04-28 00:34:50 +12:00
} else {
2023-04-29 05:46:24 +12:00
$scalingDown = true ;
$textName -> setFontSize ( 32 );
2023-04-28 00:34:50 +12:00
}
2023-04-27 20:24:53 +12:00
}
2023-04-28 19:30:30 +12:00
2023-04-29 05:46:24 +12:00
$textName -> setFontWeight ( 700 );
$textMember = new \ImagickDraw ();
$textMember -> setTextAlignment ( Imagick :: ALIGN_CENTER );
2023-04-29 20:40:22 +12:00
$textMember -> setFont ( __DIR__ . '/../../../public/fonts/Inter-Medium.ttf' );
2023-04-29 05:46:24 +12:00
$textMember -> setFillColor ( new \ImagickPixel ( $isGolden || $isPlatinum ? '#FFFFFF' : '#FFB9CC' ));
$textMember -> setFontWeight ( 500 );
$textMember -> setTextKerning ( 1.12 );
2023-04-27 20:24:53 +12:00
if ( $cardVariation === '1' ) {
2023-04-29 05:46:24 +12:00
$textMember -> setFontSize ( 21 );
2023-04-27 20:24:53 +12:00
2023-04-29 08:04:27 +12:00
$baseImage -> annotateImage ( $textName , 550 , 600 , - 22 , $name );
$baseImage -> annotateImage ( $textMember , 585 , 635 , - 22 , $memberSince );
} elseif ( $cardVariation === '2' ) {
2023-04-29 05:46:24 +12:00
$textMember -> setFontSize ( 20 );
2023-04-27 20:24:53 +12:00
2023-04-29 05:46:24 +12:00
$baseImage -> annotateImage ( $textName , 435 , 590 , 31.37 , $name );
$baseImage -> annotateImage ( $textMember , 412 , 628 , 31.37 , $memberSince );
2023-04-27 20:24:53 +12:00
} else {
2023-04-29 05:46:24 +12:00
$textMember -> setFontSize ( 16 );
$textName -> skewY ( 20 );
$textName -> skewX ( 20 );
2023-05-02 02:45:39 +12:00
$textName -> annotation ( 320 , 700 , $name );
2023-04-29 05:46:24 +12:00
$textMember -> skewY ( 20 );
$textMember -> skewX ( 20 );
$textMember -> annotation ( 330 , 735 , $memberSince );
$baseImage -> drawImage ( $textName );
$baseImage -> drawImage ( $textMember );
2023-04-27 20:24:53 +12:00
}
if ( ! empty ( $githubName )) {
$text = new \ImagickDraw ();
$text -> setTextAlignment ( Imagick :: ALIGN_LEFT );
2023-04-29 20:40:22 +12:00
$text -> setFont ( __DIR__ . '/../../../public/fonts/Inter-Regular.ttf' );
2023-04-27 20:24:53 +12:00
$text -> setFillColor ( new \ImagickPixel ( '#FFFFFF' ));
2023-05-02 02:45:39 +12:00
$text -> setFontSize ( $scalingDown ? 16 : 20 );
2023-04-27 20:24:53 +12:00
$text -> setFontWeight ( 400 );
if ( $cardVariation === '1' ) {
2023-04-29 05:46:24 +12:00
$metrics = $baseImage -> queryFontMetrics ( $text , $githubName );
$group = new Imagick ();
$groupWidth = $metrics [ 'textWidth' ] + 32 + 4 ;
2023-05-02 20:28:14 +12:00
$group -> newImage ( $groupWidth , $metrics [ 'textHeight' ] + 10 , '#00000000' );
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/github.png' );
2023-04-29 05:46:24 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
$image -> resizeImage ( 32 , 32 , Imagick :: FILTER_LANCZOS , 1 );
2023-05-02 20:28:14 +12:00
$precisionFix = - 1 ;
2023-04-29 08:04:27 +12:00
2023-04-29 05:46:24 +12:00
$group -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 0 , 0 );
$group -> annotateImage ( $text , 32 + 4 , $metrics [ 'textHeight' ] - $precisionFix , 0 , $githubName );
2023-04-27 20:24:53 +12:00
$group -> rotateImage ( new ImagickPixel ( '#00000000' ), - 22 );
2023-04-28 00:34:50 +12:00
$x = 510 - $group -> getImageWidth () / 2 ;
$y = 530 - $group -> getImageHeight () / 2 ;
$baseImage -> compositeImage ( $group , Imagick :: COMPOSITE_OVER , $x , $y );
2023-04-29 08:04:27 +12:00
} elseif ( $cardVariation === '2' ) {
2023-04-29 05:46:24 +12:00
$metrics = $baseImage -> queryFontMetrics ( $text , $githubName );
2023-04-29 08:04:27 +12:00
2023-04-29 05:46:24 +12:00
$group = new Imagick ();
$groupWidth = $metrics [ 'textWidth' ] + 32 + 4 ;
2023-05-02 20:28:14 +12:00
$group -> newImage ( $groupWidth , $metrics [ 'textHeight' ] + 10 , '#00000000' );
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/github.png' );
2023-04-29 05:46:24 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
$image -> resizeImage ( 32 , 32 , Imagick :: FILTER_LANCZOS , 1 );
2023-05-02 20:28:14 +12:00
$precisionFix = - 1 ;
2023-04-29 08:04:27 +12:00
2023-04-29 05:46:24 +12:00
$group -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 0 , 0 );
$group -> annotateImage ( $text , 32 + 4 , $metrics [ 'textHeight' ] - $precisionFix , 0 , $githubName );
2023-04-28 00:34:50 +12:00
$group -> rotateImage ( new ImagickPixel ( '#00000000' ), 31.11 );
$x = 485 - $group -> getImageWidth () / 2 ;
$y = 530 - $group -> getImageHeight () / 2 ;
$baseImage -> compositeImage ( $group , Imagick :: COMPOSITE_OVER , $x , $y );
2023-04-29 05:46:24 +12:00
} else {
$text -> skewY ( 20 );
$text -> skewX ( 20 );
$text -> setTextAlignment ( \Imagick :: ALIGN_CENTER );
2023-05-02 02:45:39 +12:00
$text -> annotation ( 320 + 15 + 2 , 640 , $githubName );
2023-04-29 05:46:24 +12:00
$metrics = $baseImage -> queryFontMetrics ( $text , $githubName );
2023-04-29 20:40:22 +12:00
$image = new Imagick ( __DIR__ . '/../../../public/images/cards/cloud/github-skew.png' );
2023-04-29 05:46:24 +12:00
$image -> setGravity ( Imagick :: GRAVITY_CENTER );
2023-05-02 02:45:39 +12:00
$baseImage -> compositeImage ( $image , Imagick :: COMPOSITE_OVER , 512 - ( $metrics [ 'textWidth' ] / 2 ), 518 + \strlen ( $githubName ) * 1.3 );
2023-04-29 05:46:24 +12:00
$baseImage -> drawImage ( $text );
2023-04-27 20:24:53 +12:00
}
}
2023-04-26 23:06:11 +12:00
if ( ! empty ( $width ) || ! empty ( $height )) {
$baseImage -> resizeImage ( $width , $height , Imagick :: FILTER_LANCZOS , 1 );
}
$response
-> addHeader ( 'Expires' , \date ( 'D, d M Y H:i:s' , \time () + ( 60 * 60 * 24 * 45 )) . ' GMT' ) // 45 days cache
-> setContentType ( 'image/png' )
-> file ( $baseImage -> getImageBlob ());
2020-12-27 03:59:15 +13:00
});