Improve tests

This commit is contained in:
Daniil Gentili 2020-02-09 16:24:57 +01:00
parent 3b21304d8b
commit 47228712a6
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
11 changed files with 276 additions and 74 deletions

View File

@ -31,7 +31,7 @@
"amphp/http-client-cookies": "^1",
"amphp/uri": "^0.1",
"danog/tg-file-decoder": "^0.1",
"danog/magicalserializer": "^1.0",
"danog/magicalserializer": "^1.0"
},
"require-dev": {
"vlucas/phpdotenv": "^3",
@ -41,7 +41,7 @@
"amphp/php-cs-fixer-config": "dev-master",
"haydenpierce/class-finder": "^0.4",
"amphp/http-server": "dev-master",
"amphp/http": "^1.6"
"amphp/http": "^1.6",
"amphp/websocket-client": "dev-master as 1",
"amphp/websocket": "dev-master as 1",
"ext-ctype": "*",

View File

@ -19,6 +19,8 @@
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
use Amp\Http\Server\HttpServer;
use danog\MadelineProto\API;
use danog\MadelineProto\Logger;
use danog\MadelineProto\RPCErrorException;
use League\Uri\Contracts\UriException;
@ -47,17 +49,32 @@ class EventHandler extends \danog\MadelineProto\EventHandler
"Max 1.5GB, parallel upload and download powered by @MadelineProto.";
const ADMIN = 'danogentili';
/**
* Whether to allow uploads.
*/
private $UPLOAD;
/**
* Array of media objects.
*
* @var array
*/
private $states = [];
/**
* Constructor.
*
* @param API $API API
*/
public function __construct($API)
{
$this->UPLOAD = \class_exists(HttpServer::class);
parent::__construct($API);
}
public function onUpdateNewChannelMessage($update)
{
//yield $this->onUpdateNewMessage($update);
}
public function report($message)
public function report(string $message)
{
try {
$this->messages->sendMessage(['peer' => self::ADMIN, 'message' => $message]);
@ -79,10 +96,21 @@ class EventHandler extends \danog\MadelineProto\EventHandler
$peerId = $peer['bot_api_id'];
$messageId = $update['message']['id'];
if ($this->UPLOAD && $update['message']['message'] === '/getUrl') {
yield $this->messages->sendMessage(['peer' => $peerId, 'message' => 'Give me a file: ', 'reply_to_msg_id' => $messageId]);
$this->states[$peerId] = $this->UPLOAD;
}
if ($update['message']['message'] === '/start') {
return $this->messages->sendMessage(['peer' => $peerId, 'message' => self::START, 'parse_mode' => 'Markdown', 'reply_to_msg_id' => $messageId]);
}
if (isset($update['message']['media']['_']) && $update['message']['media']['_'] !== 'messageMediaWebPage') {
if ($this->UPLOAD && ($this->states[$peerId] ?? false) === $this->UPLOAD) {
$media = yield $this->getDownloadInfo($this->states[$peerId]);
unset($media['MessageMedia']);
$media = yield
unset($this->states[$peerId]);
return;
}
yield $this->messages->sendMessage(['peer' => $peerId, 'message' => 'Give me a new name for this file: ', 'reply_to_msg_id' => $messageId]);
$this->states[$peerId] = $update['message']['media'];
@ -184,7 +212,7 @@ $settings = [
]
],
'upload' => [
'allow_automatic_upload' => false, // IMPORTANT: for security reasons, upload by URL will still be allowed
'allow_automatic_upload' => false // IMPORTANT: for security reasons, upload by URL will still be allowed
],
];

View File

@ -25,7 +25,7 @@ class Exception extends \Exception
public static $rollbar = true;
public function __toString()
{
return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception' . ($this->message !== '' ? ': ' : '') . $this->message . ' in ' . $this->file . ':' . $this->line . PHP_EOL . \danog\MadelineProto\Magic::$revision . PHP_EOL . 'TL Trace:' . PHP_EOL . $this->getTLTrace();
return $this->file === 'MadelineProto' ? $this->message : '\\danog\\MadelineProto\\Exception'.($this->message !== '' ? ': ' : '').$this->message.' in '.$this->file.':'.$this->line.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace:'.PHP_EOL.$this->getTLTrace();
}
public function __construct($message = null, $code = 0, self $previous = null, $file = null, $line = null)
{
@ -37,8 +37,10 @@ class Exception extends \Exception
$this->line = $line;
}
parent::__construct($message, $code, $previous);
if (\strpos($message, 'socket_accept') === false) {
\danog\MadelineProto\Logger::log($message . ' in ' . \basename($this->file) . ':' . $this->line, \danog\MadelineProto\Logger::FATAL_ERROR);
if (\strpos($message, 'socket_accept') === false
&& !\in_array(\basename($this->file), ['PKCS8.php', 'PSS.php'])
) {
\danog\MadelineProto\Logger::log($message.' in '.\basename($this->file).':'.$this->line, \danog\MadelineProto\Logger::FATAL_ERROR);
}
if (\in_array($message, ['The session is corrupted!', 'Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden', 'The php-libtgvoip extension is required to accept and manage calls. See daniil.it/MadelineProto for more info.', 'File does not exist', 'Please install this fork of phpseclib: https://github.com/danog/tgseclib'])) {
return;
@ -50,17 +52,24 @@ class Exception extends \Exception
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, \debug_backtrace(0));
}
}
public static function extension(string $extensionName)
/**
* Complain about missing extensions
*
* @param string $extensionName Extension name
*
* @return self
*/
public static function extension(string $extensionName): self
{
$additional = 'Try running sudo apt-get install php' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '-' . $extensionName . '.';
$additional = 'Try running sudo apt-get install php'.PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION.'-'.$extensionName.'.';
if ($extensionName === 'libtgvoip') {
$additional = 'Follow the instructions @ https://voip.madelineproto.xyz to install it.';
} elseif ($extensionName === 'prime') {
$additional = 'Follow the instructions @ https://prime.madelineproto.xyz to install it.';
}
$message = 'MadelineProto requires the ' . $extensionName . ' extension to run. ' . $additional;
$message = 'MadelineProto requires the '.$extensionName.' extension to run. '.$additional;
if (PHP_SAPI !== 'cli') {
echo $message . '<br>';
echo $message.'<br>';
}
$file = 'MadelineProto';
$line = 1;

View File

@ -194,6 +194,13 @@ class MTProto extends AsyncConstruct implements TLCallback
'msg_resend_ans_req',
];
const DEFAULT_GETUPDATES_PARAMS = ['offset' => 0, 'limit' => null, 'timeout' => 0];
const POWERED_BY = "<p><small>Powered by <a href='https://docs.madelineproto.xyz'>MadelineProto</a></small></p>";
const NO_CACHE = [
'Cache-Control' => ['no-store, no-cache, must-revalidate, max-age=0', 'post-check=0, pre-check=0'],
'Pragma' => 'no-cache'
];
/**
* Instance of wrapper API.
*

View File

@ -513,7 +513,7 @@ trait ResponseHandler
$r = isset($response['_']) ? $response['_'] : \json_encode($response);
$this->logger->logger("Deferred: sent {$r} to deferred", Logger::ULTRA_VERBOSE);
if ($botAPI) {
$response = (yield from $this->MTProtoToBotAPI($response));
$response = (yield from $this->API->MTProtoToBotAPI($response));
}
if (isset($this->outgoing_messages[$request_id]['promise'])) {
// This should not happen but happens, should debug

View File

@ -549,9 +549,8 @@ trait Files
$constructor = $constructor['MessageMedia'];
} elseif (isset($constructor['InputMedia'])) {
return $constructor;
} else {
$constructor = (yield from $this->getPwrChat($constructor['Chat'] ?? $constructor['User']));
$constructor = $constructor['photo'];
} else if (isset($constructor['Chat']) || isset($constructor['User'])) {
throw new Exception("Chat photo file IDs can't be reused to resend chat photos, please use getPwrChat()['photo'], instead");
}
}
switch ($constructor['_']) {
@ -800,9 +799,6 @@ trait Files
throw new \danog\MadelineProto\Exception('Invalid constructor provided: '.$messageMedia['_']);
}
}
private const POWERED_BY = "<p><small>Powered by <a href='https://docs.madelineproto.xyz'>MadelineProto</a></small></p>";
/**
* Download file to browser.
*
@ -841,7 +837,7 @@ trait Files
\header("$key: $subValue");
}
}
http_response_code($result['code']);
\http_response_code($result['code']);
if (!\in_array($result['code'], [Status::OK, Status::PARTIAL_CONTENT])) {
yield Tools::echo(self::getExplanation($result['code']));
@ -913,10 +909,6 @@ trait Files
$body .= "</body></html>";
return $body;
}
private const NO_CACHE = [
'Cache-Control' => ['no-store, no-cache, must-revalidate, max-age=0', 'post-check=0, pre-check=0'],
'Pragma' => 'no-cache'
];
/**
* Parse headers.
*

View File

@ -20,6 +20,11 @@
namespace danog\MadelineProto\MTProtoTools;
use Amp\Http\Client\Request;
use danog\Decoder\FileId;
use danog\Decoder\PhotoSizeSource\PhotoSizeSourceDialogPhoto;
use const danog\Decoder\PHOTO;
use const danog\Decoder\PROFILE_PHOTO;
/**
* Manages peers.
@ -705,7 +710,7 @@ trait PeerHandler
*
* @return \Generator<array> Chat object
*/
public function getPwrChat($id, $fullfetch = true, $send = true): \Generator
public function getPwrChat($id, bool $fullfetch = true, bool $send = true): \Generator
{
$full = $fullfetch ? yield from $this->getFullInfo($id) : (yield from $this->getInfo($id));
$res = ['id' => $full['bot_api_id'], 'type' => $full['type']];
@ -837,6 +842,34 @@ trait PeerHandler
if ($fullfetch || $send) {
$this->storeDb($res);
}
if (isset($res['photo'])) {
$photo = [];
foreach ([
'small' => $res['photo']['sizes'][0],
'big' => end($res['photo']['sizes']),
] as $type => $size) {
$fileId = new FileId;
$fileId->setId($res['photo']['id'] ?? 0);
$fileId->setAccessHash($res['photo']['access_hash'] ?? 0);
$fileId->setFileReference($res['photo']['file_reference'] ?? '');
$fileId->setDcId($res['photo']['dc_id']);
$fileId->setType(PROFILE_PHOTO);
$fileId->setLocalId($size['location']['local_id']);
$fileId->setVolumeId($size['location']['volume_id']);
$photoSize = new PhotoSizeSourceDialogPhoto;
$photoSize->setDialogId($res['id']);
$photoSize->setDialogPhotoSmall($type === 'small');
$photoSize->setDialogAccessHash($res['access_hash'] ?? 0);
$fileId->setPhotoSizeSource($photoSize);
$photo[$type.'_file_id'] = (string) $fileId;
$photo[$type.'_file_unique_id'] = $fileId->getUniqueBotAPI();
}
$res['photo'] += $photo;
}
return $res;
}
private function recurseAlphabetSearchParticipants($channel, $filter, $q, $total_count, &$res): \Generator

View File

@ -83,7 +83,6 @@ class RSA
*/
public function encrypt($data): string
{
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['rsa_encrypting'], Logger::VERBOSE);
return (new \tgseclib\Math\BigInteger((string) $data, 256))->powMod($this->e, $this->n)->toBytes();
}
}

View File

@ -19,8 +19,11 @@
namespace danog\MadelineProto\TL\Conversion;
use danog\Decoder\FileId;
use danog\MadelineProto\Logger;
use const danog\Decoder\TYPES_IDS;
trait BotAPI
{
private function htmlEntityDecode(string $stuff): string
@ -174,16 +177,15 @@ trait BotAPI
* Convert MTProto parameters to bot API parameters.
*
* @param array $data Data
* @param array $sent_arguments Sent arguments
*
* @return \Generator<array>
*/
public function MTProtoToBotAPI(array $data, array $sent_arguments = []): \Generator
public function MTProtoToBotAPI(array $data): \Generator
{
$newd = [];
if (!isset($data['_'])) {
foreach ($data as $key => $element) {
$newd[$key] = (yield from $this->MTProtoToBotAPI($element, $sent_arguments));
$newd[$key] = (yield from $this->MTProtoToBotAPI($element));
}
return $newd;
}
@ -191,18 +193,20 @@ trait BotAPI
case 'updateShortSentMessage':
$newd['message_id'] = $data['id'];
$newd['date'] = $data['date'];
$newd['text'] = $sent_arguments['message'];
$newd['text'] = $data['request']['message'];
if ($data['out']) {
$newd['from'] = (yield from $this->getPwrChat($this->authorization['user']));
}
$newd['chat'] = (yield from $this->getPwrChat($sent_arguments['peer']));
$newd['chat'] = yield from $this->getPwrChat($data['request']['peer']);
if (isset($data['entities'])) {
$newd['entities'] = (yield from $this->MTProtoToBotAPI($data['entities'], $sent_arguments));
$newd['entities'] = yield from $this->MTProtoToBotAPI($data['entities']);
}
if (isset($data['media'])) {
$newd = \array_merge($newd, yield from $this->MTProtoToBotAPI($data['media'], $sent_arguments));
$newd += yield from $this->MTProtoToBotAPI($data['media']);
}
return $newd;
case 'updates':
$data = array_values(array_filter($data['updates'], fn(array $update) => $update['_'] !== 'updateMessageID'))[0];
case 'updateNewChannelMessage':
case 'updateNewMessage':
return yield from $this->MTProtoToBotAPI($data['message']);
@ -217,7 +221,7 @@ trait BotAPI
}
$newd['chat'] = (yield from $this->getPwrChat($data['to_id']));
if (isset($data['entities'])) {
$newd['entities'] = (yield from $this->MTProtoToBotAPI($data['entities'], $sent_arguments));
$newd['entities'] = (yield from $this->MTProtoToBotAPI($data['entities']));
}
if (isset($data['views'])) {
$newd['views'] = $data['views'];
@ -241,7 +245,7 @@ trait BotAPI
$newd['forward_from_message_id'] = $data['fwd_from']['channel_post'];
}
if (isset($data['media'])) {
$newd = \array_merge($newd, yield from $this->MTProtoToBotAPI($data['media'], $sent_arguments));
$newd = \array_merge($newd, yield from $this->MTProtoToBotAPI($data['media']));
}
return $newd;
case 'messageEntityMention':
@ -297,7 +301,7 @@ trait BotAPI
$res['photo'] = [];
foreach ($data['photo']['sizes'] as $key => $photo) {
if (\in_array($photo['_'], ['photoCachedSize', 'photoSize'])) {
$res['photo'][$key] = (yield from $this->photosizeToBotAPI($photo, $data['photo']));
$res['photo'][$key] = $this->photosizeToBotAPI($photo, $data['photo']);
}
}
return $res;
@ -307,21 +311,18 @@ trait BotAPI
$type_name = 'document';
$res = [];
if (isset($data['document']['thumbs']) && $data['document']['thumbs'] && \in_array(\end($data['document']['thumbs'])['_'], ['photoCachedSize', 'photoSize'])) {
$res['thumb'] = (yield from $this->photosizeToBotAPI(\end($data['document']['thumbs']), [], true));
$res['thumb'] = $this->photosizeToBotAPI(\end($data['document']['thumbs']), $data['document'], true);
}
foreach ($data['document']['attributes'] as $attribute) {
switch ($attribute['_']) {
case 'documentAttributeFilename':
$pathinfo = \pathinfo($attribute['file_name']);
$res['ext'] = isset($pathinfo['extension']) ? '.' . $pathinfo['extension'] : '';
$res['ext'] = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : '';
$res['file_name'] = $pathinfo['filename'];
break;
case 'documentAttributeAudio':
$audio = $attribute;
$type_name = 'audio';
if ($attribute['voice']) {
$type_name = 'voice';
}
$type_name = $attribute['voice'] ? 'voice' :'audio';
$res['duration'] = $attribute['duration'];
if (isset($attribute['performer'])) {
$res['performer'] = $attribute['performer'];
@ -344,7 +345,7 @@ trait BotAPI
$res['height'] = $attribute['h'];
break;
case 'documentAttributeAnimated':
$type_name = 'gif';
$type_name = 'animation';
$res['animated'] = true;
break;
case 'documentAttributeHasStickers':
@ -364,24 +365,32 @@ trait BotAPI
if (isset($audio) && isset($audio['title']) && !isset($res['file_name'])) {
$res['file_name'] = $audio['title'];
if (isset($audio['performer'])) {
$res['file_name'] .= ' - ' . $audio['performer'];
$res['file_name'] .= ' - '.$audio['performer'];
}
}
if (!isset($res['file_name'])) {
$res['file_name'] = $data['document']['access_hash'];
}
$res['file_name'] .= '_' . $data['document']['id'];
$res['file_name'] .= '_'.$data['document']['id'];
if (isset($res['ext'])) {
$res['file_name'] .= $res['ext'];
unset($res['ext']);
} else {
$res['file_name'] .= $this->getExtensionFromMime($data['document']['mime_type']);
}
$data['document']['_'] = 'bot_' . $type_name;
$res['file_size'] = $data['document']['size'];
$res['mime_type'] = $data['document']['mime_type'];
$res['file_id'] = \danog\MadelineProto\Tools::base64urlEncode(\danog\MadelineProto\Tools::rleEncode(yield from $this->TL->serializeObject(['type' => 'File'], $data['document'], 'File') . \chr(2)));
return [$type_name => $res, 'caption' => isset($data['caption']) ? $data['caption'] : ''];
$fileId = new FileId;
$fileId->setId($data['document']['id']);
$fileId->setAccessHash($data['document']['access_hash']);
$fileId->setFileReference($data['document']['file_reference'] ?? '');
$fileId->setDcId($data['document']['dc_id']);
$fileId->setType(TYPES_IDS[$type_name]);
$res['file_id'] = (string) $fileId;
$res['file_unique_id'] = $fileId->getUniqueBotAPI();
return [$type_name => $res, 'caption' => $data['caption'] ?? ''];
default:
throw new Exception(\sprintf(\danog\MadelineProto\Lang::$current_lang['botapi_conversion_error'], $data['_']));
}
@ -586,7 +595,7 @@ trait BotAPI
$multiple_args = [$multiple_args_base];
$i = 0;
foreach ($text_arr as $word) {
if ($this->mbStrlen($multiple_args[$i]['message'] . $word) <= $max_length) {
if ($this->mbStrlen($multiple_args[$i]['message'].$word) <= $max_length) {
$multiple_args[$i]['message'] .= $word;
} else {
$i++;
@ -670,7 +679,7 @@ trait BotAPI
foreach ($initialArray as $item) {
$delimOffset += $this->mbStrlen($item);
//if ($this->mbStrlen($item) > 0) {
$finalArray[] = $item . ($delimOffset < $this->mbStrlen($string) ? $string[$delimOffset] : '');
$finalArray[] = $item.($delimOffset < $this->mbStrlen($string) ? $string[$delimOffset] : '');
//}
$delimOffset++;
}

View File

@ -39,17 +39,38 @@ use const danog\Decoder\VOICE;
trait BotAPIFiles
{
private function photosizeToBotAPI($photoSize, $photo, $thumbnail = false): \Generator
private function photosizeToBotAPI($photoSize, $photo, $thumbnail = false): array
{
$ext = '.jpg';
//$this->getExtensionFromLocation(['_' => 'inputFileLocation', 'volume_id' => $photoSize['location']['volume_id'], 'local_id' => $photoSize['location']['local_id'], 'secret' => $photoSize['location']['secret'], 'dc_id' => $photoSize['location']['dc_id']], '.jpg');
$photoSize['location']['access_hash'] = $photo['access_hash'] ?? 0;
$photoSize['location']['id'] = $photo['id'] ?? 0;
$photoSize['location']['secret'] = $photo['location']['secret'] ?? 0;
$photoSize['location']['dc_id'] = $photo['dc_id'] ?? 0;
$photoSize['location']['_'] = $thumbnail ? 'bot_thumbnail' : 'bot_photo';
$data = (yield from $this->TL->serializeObject(['type' => 'File'], $photoSize['location'], 'File')).\chr(2);
return ['file_id' => \danog\MadelineProto\Tools::base64urlEncode(\danog\MadelineProto\Tools::rleEncode($data)), 'width' => $photoSize['w'], 'height' => $photoSize['h'], 'file_size' => isset($photoSize['size']) ? $photoSize['size'] : \strlen($photoSize['bytes']), 'mime_type' => 'image/jpeg', 'file_name' => $photoSize['location']['volume_id'].'_'.$photoSize['location']['local_id'].$ext];
$fileId = new FileId;
$fileId->setId($photo['id'] ?? 0);
$fileId->setAccessHash($photo['access_hash'] ?? 0);
$fileId->setFileReference($photo['file_reference'] ?? '');
$fileId->setDcId($photo['dc_id'] ?? 0);
$fileId->setLocalId($photoSize['location']['local_id']);
$fileId->setVolumeId($photoSize['location']['volume_id']);
$photoSizeSource = new PhotoSizeSourceThumbnail;
$photoSizeSource->setThumbType($photoSize['type']);
if ($photo['_'] === 'photo') {
$photoSizeSource->setThumbFileType(PHOTO);
$fileId->setType(PHOTO);
} else {
$photoSizeSource->setThumbFileType(THUMBNAIL);
$fileId->setType(THUMBNAIL);
}
$fileId->setPhotoSizeSource($photoSizeSource);
return [
'file_id' => (string) $fileId,
'file_unique_id' => $fileId->getUniqueBotAPI(),
'width' => $photoSize['w'],
'height' => $photoSize['h'],
'file_size' => $photoSize['size'] ?? \strlen($photoSize['bytes']),
'mime_type' => 'image/jpeg',
'file_name' => $photoSize['location']['volume_id'].'_'.$photoSize['location']['local_id'].'.jpg'
];
}
/**
* Unpack bot API file ID.

View File

@ -40,6 +40,54 @@ class FileIdTest extends TestCase
self::$MadelineProto->botLogin(\getenv('BOT_TOKEN'));
}
/**
* Strip file reference from file ID.
*
* @param string $fileId File ID
*
* @return string
*/
public static function stripFileReference(string $fileId): string
{
return FileId::fromBotAPI($fileId)->setFileReference('');
}
/**
* Strip access hash (and possibly ID) from file ID.
*
* @param string $fileId File ID
*
* @return string
*/
public static function stripForChat(string $fileId): string
{
$file = FileId::fromBotAPI($fileId)->setAccessHash(0);
if ($file->getPhotoSizeSource()->getDialogId() < 0) {
$file->setId(0);
}
return $file;
}
/**
* Asserts that two file IDs are equal.
*
* @param string $fileIdAstr File ID A
* @param string $fileIdBstr File ID B
* @param string $message Message
*
* @throws PHPUnit\Framework\AssertionFailedError
*
* @return void
*/
public static function assertFileIdEquals(string $fileIdAstr, string $fileIdBstr, $message = '')
{
$fileIdAstr = self::stripFileReference($fileIdAstr);
$fileIdBstr = self::stripFileReference($fileIdBstr);
if ($fileIdAstr !== $fileIdBstr) {
\var_dump(FileId::fromBotAPI($fileIdAstr), FileId::fromBotAPI($fileIdBstr));
}
self::assertEquals($fileIdAstr, $fileIdBstr, $message);
}
/**
* @param string $fileId File ID
* @param string $type Expected type
@ -47,7 +95,7 @@ class FileIdTest extends TestCase
*
* @dataProvider provideFileIdsAndType
*/
public function testDownload(string $type, string $fileIdStr, string $origType)
public function testDownload(string $type, string $fileIdStr, string $uniqueFileIdStr, array $fullInfo)
{
self::$MadelineProto->logger("Trying to download $fileIdStr");
self::$MadelineProto->downloadToFile($fileIdStr, '/dev/null');
@ -60,16 +108,62 @@ class FileIdTest extends TestCase
*
* @dataProvider provideFileIdsAndType
*/
public function testResend(string $type, string $fileIdStr, string $origType)
public function testResendConvert(string $type, string $fileIdStr, string $uniqueFileIdStr, array $fullInfo)
{
self::$MadelineProto->logger("Trying to resend $fileIdStr");
self::$MadelineProto->messages->sendMedia(
self::$MadelineProto->logger("Trying to resend and then reconvert $fileIdStr");
if ($type === 'profile_photo') {
$chat = self::$MadelineProto->getPwrChat($fullInfo['chat']);
$this->assertArrayHasKey('photo', $chat);
$chat = $chat['photo'];
$this->assertArrayHasKey($fullInfo['type'].'_file_id', $chat);
$this->assertArrayHasKey($fullInfo['type'].'_file_unique_id', $chat);
$chat[$fullInfo['type'].'_file_id'] = self::stripForChat($chat[$fullInfo['type'].'_file_id']);
$this->assertFileIdEquals($fileIdStr, $chat[$fullInfo['type'].'_file_id']);
$this->assertEquals($uniqueFileIdStr, $chat[$fullInfo['type'].'_file_unique_id']);
$this->expectExceptionMessage("Chat photo file IDs can't be reused to resend chat photos, please use getPwrChat()['photo'], instead");
}
$res = self::$MadelineProto->messages->sendMedia(
[
'peer' => \getenv('DEST'),
'media' => $fileIdStr
],
[
'botAPI' => true
]
);
$this->assertTrue(true);
if ($type === 'thumbnail') {
$this->assertArrayHasKey($fullInfo[0], $res);
$res = $res[$fullInfo[0]];
$this->assertArrayHasKey('thumb', $res);
$this->assertFileIdEquals($fileIdStr, $res['thumb']['file_id']);
$this->assertEquals($uniqueFileIdStr, $res['thumb']['file_unique_id']);
list($type, $fileIdStr, $uniqueFileIdStr) = $fullInfo;
} else {
$this->assertArrayHasKey($type, $res);
$res = $res[$type];
}
$hasFileId = false;
$hasFileUniqueId = false;
$res = $type === 'photo' ? $res : [$res];
foreach ($res as $subRes) {
$this->assertArrayHasKey('file_id', $subRes);
$this->assertArrayHasKey('file_unique_id', $subRes);
$hasFileId |= self::stripFileReference($fileIdStr) === self::stripFileReference($subRes['file_id']);
$hasFileUniqueId |= $uniqueFileIdStr === $subRes['file_unique_id'];
}
if (\count($res) === 1) {
$this->assertFileIdEquals($fileIdStr, $res[0]['file_id']);
$this->assertEquals($uniqueFileIdStr, $res[0]['file_unique_id']);
} else {
$this->assertTrue((bool) $hasFileUniqueId);
$this->assertTrue((bool) $hasFileId);
}
}
public function provideFileIdsAndType(): \Generator
@ -77,16 +171,21 @@ class FileIdTest extends TestCase
$dest = \getenv('DEST');
$token = \getenv('BOT_TOKEN');
foreach ($this->provideChats() as $chat) {
$result = \json_decode(\file_get_contents("https://api.telegram.org/bot$token/getChat?chat_id=$chat"), true)['result']['photo'];
$result = \json_decode(\file_get_contents("https://api.telegram.org/bot$token/getChat?chat_id=$chat"), true)['result']['photo'] ?? [];
if (!$result) {
continue;
}
yield [
'profile_photo',
$result['small_file_id'],
'profile_photo',
$result['small_file_unique_id'],
['chat' => $chat, 'type' => 'small'],
];
yield [
'profile_photo',
$result['big_file_id'],
'profile_photo',
$result['big_file_unique_id'],
['chat' => $chat, 'type' => 'big'],
];
}
foreach ($this->provideUrls() as $type => $url) {
@ -111,16 +210,18 @@ class FileIdTest extends TestCase
$botResult = [$botResult];
}
foreach ($botResult as $subResult) {
yield [
yield $full = [
$type,
$subResult['file_id'],
$type,
$subResult['file_unique_id'],
[],
];
if (isset($subResult['thumb'])) {
yield [
'thumbnail',
$subResult['thumb']['file_id'],
$type,
$subResult['thumb']['file_unique_id'],
$full,
];
}
}
@ -129,11 +230,11 @@ class FileIdTest extends TestCase
}
public function provideChats(): array
{
return [\getenv('DEST'), '@MadelineProto'];
return [\getenv('DEST'), '@MadelineProto', -382346236];
}
public function provideUrls(): array
{
return [
$res = [
'sticker' => 'https://github.com/danog/MadelineProto/blob/master/tests/lel.webp?raw=true',
'photo' => 'https://github.com/danog/MadelineProto/blob/master/tests/faust.jpg',
'audio' => 'https://github.com/danog/MadelineProto/blob/master/tests/mosconi.mp3?raw=true',
@ -141,7 +242,10 @@ class FileIdTest extends TestCase
'animation' => 'https://github.com/danog/MadelineProto/blob/master/tests/pony.mp4?raw=true',
'document' => 'https://github.com/danog/danog.github.io/raw/master/lol/index_htm_files/0.gif',
'voice' => 'https://daniil.it/audio_2020-02-01_18-09-08.ogg',
'video_note' => 'https://daniil.it/round.mp4'
];
if (\getenv('TRAVIS_COMMIT')) {
$res['video_note'] = 'https://daniil.it/round.mp4';
}
return $res;
}
}