Repository: def-studio/telegraph (php)

Issue:
send photo/doc with fileId
send photo/document with file_id in telegram

Pull request description:
[feat] attachments remote url and file_id
closes #149

Patch:
diff --git a/docs/content/en/features/attachments.md b/docs/content/en/features/attachments.md
index 6fbecbb0..fb37c867 100644
--- a/docs/content/en/features/attachments.md
+++ b/docs/content/en/features/attachments.md
@@ -7,7 +7,7 @@ fullscreen: false
 position: 36
 ---
 
-Telegraph supports different types of attachments
+Telegraph supports different types of attachments both from local files, remote urls and existing files on Telegram servers (using their file_id)
 
 ## Attachment types
 
@@ -17,6 +17,8 @@ Photos can be sent through Telegraph `->photo()` method:
 
 ```php
 Telegraph::photo(Storage::path('photo.jpg'))->send();
+Telegraph::photo('https://my-repository/photo.jpg')->send();
+Telegraph::photo($telegramFileId)->send();
 ```
 
 
@@ -26,6 +28,8 @@ Photos can be sent through Telegraph `->voice()` method:
 
 ```php
 Telegraph::voice(Storage::path('voice.ogg'))->send();
+Telegraph::voice('https://my-repository/voice.ogg')->send();
+Telegraph::voice($telegramFileId)->send();
 ```
 
 
@@ -35,6 +39,8 @@ Documents can be sent through Telegraph `->document()` method:
 
 ```php
 Telegraph::document(Storage::path('my_document.pdf'))->send();
+Telegraph::document('https://my-repository/my_document.pdf')->send();
+Telegraph::document($telegramFileId)->send();
 ```
 
 ### Location
diff --git a/src/Concerns/SendsAttachments.php b/src/Concerns/SendsAttachments.php
index c81c9da9..4bb7d814 100644
--- a/src/Concerns/SendsAttachments.php
+++ b/src/Concerns/SendsAttachments.php
@@ -63,15 +63,17 @@ trait SendsAttachments
     {
         $telegraph = clone $this;
 
-        if (!File::exists($path)) {
-            throw FileException::fileNotFound('Voice', $path);
-        }
-
         $telegraph->endpoint = self::ENDPOINT_SEND_VOICE;
 
         $telegraph->data['chat_id'] = $telegraph->getChat()->chat_id;
 
-        $telegraph->files->put('voice', new Attachment($path, $filename));
+        if (File::exists($path)) {
+            $telegraph->files->put('voice', new Attachment($path, $filename));
+
+            return $telegraph;
+        }
+
+        $telegraph->data['voice'] = $path;
 
         return $telegraph;
     }
@@ -80,19 +82,22 @@ trait SendsAttachments
     {
         $telegraph = clone $this;
 
-        if (!File::exists($path)) {
-            throw FileException::fileNotFound("Document", $path);
-        }
-
-        if (($size = $telegraph->fileSizeInMb($path)) > Telegraph::MAX_DOCUMENT_SIZE_IN_MB) {
-            throw FileException::documentSizeExceeded($size);
-        }
-
         $telegraph->endpoint = self::ENDPOINT_SEND_DOCUMENT;
 
         $telegraph->data['chat_id'] = $telegraph->getChat()->chat_id;
 
-        $telegraph->files->put('document', new Attachment($path, $filename));
+
+        if (File::exists($path)) {
+            if (($size = $telegraph->fileSizeInMb($path)) > Telegraph::MAX_DOCUMENT_SIZE_IN_MB) {
+                throw FileException::documentSizeExceeded($size);
+            }
+
+            $telegraph->files->put('document', new Attachment($path, $filename));
+
+            return $telegraph;
+        }
+
+        $telegraph->data['document'] = $path;
 
         return $telegraph;
     }
@@ -110,27 +115,29 @@ trait SendsAttachments
     {
         $telegraph = clone $this;
 
-        if (!File::exists($path)) {
-            throw FileException::fileNotFound("Thumbnail", $path);
-        }
+        if (File::exists($path)) {
+            if (($size = $telegraph->fileSizeInKb($path)) > Telegraph::MAX_THUMBNAIL_SIZE_IN_KB) {
+                throw FileException::thumbnailSizeExceeded($size);
+            }
 
-        if (($size = $telegraph->fileSizeInKb($path)) > Telegraph::MAX_THUMBNAIL_SIZE_IN_KB) {
-            throw FileException::thumbnailSizeExceeded($size);
-        }
+            if (($height = $telegraph->imageHeight($path)) > Telegraph::MAX_THUMBNAIL_HEIGHT) {
+                throw FileException::thumbnailHeightExceeded($height);
+            }
 
-        if (($height = $telegraph->imageHeight($path)) > Telegraph::MAX_THUMBNAIL_HEIGHT) {
-            throw FileException::thumbnailHeightExceeded($height);
-        }
+            if (($width = $telegraph->imageWidth($path)) > Telegraph::MAX_THUMBNAIL_WIDTH) {
+                throw FileException::thumbnailWidthExceeded($width);
+            }
 
-        if (($width = $telegraph->imageWidth($path)) > Telegraph::MAX_THUMBNAIL_WIDTH) {
-            throw FileException::thumbnailWidthExceeded($width);
-        }
+            if (!Str::of($ext = File::extension($path))->lower()->is('jpg')) {
+                throw FileException::invalidThumbnailExtension($ext);
+            }
+
+            $telegraph->files->put('thumb', new Attachment($path));
 
-        if (!Str::of($ext = File::extension($path))->lower()->is('jpg')) {
-            throw FileException::invalidThumbnailExtension($ext);
+            return $telegraph;
         }
 
-        $telegraph->files->put('thumb', new Attachment($path));
+        $telegraph->data['thumb'] = $path;
 
         return $telegraph;
     }
@@ -139,30 +146,32 @@ trait SendsAttachments
     {
         $telegraph = clone $this;
 
-        if (!File::exists($path)) {
-            throw FileException::fileNotFound('Photo', $path);
-        }
+        $telegraph->endpoint = self::ENDPOINT_SEND_PHOTO;
 
-        if (($size = $telegraph->fileSizeInMb($path)) > Telegraph::MAX_PHOTO_SIZE_IN_MB) {
-            throw FileException::photoSizeExceeded($size);
-        }
+        $telegraph->data['chat_id'] = $telegraph->getChat()->chat_id;
 
-        $height = $telegraph->imageHeight($path);
-        $width = $telegraph->imageWidth($path);
+        if (File::exists($path)) {
+            if (($size = $telegraph->fileSizeInMb($path)) > Telegraph::MAX_PHOTO_SIZE_IN_MB) {
+                throw FileException::photoSizeExceeded($size);
+            }
 
-        if (($totalLength = $height + $width) > Telegraph::MAX_PHOTO_HEIGHT_WIDTH_TOTAL) {
-            throw FileException::invalidPhotoSize($totalLength);
-        }
+            $height = $telegraph->imageHeight($path);
+            $width = $telegraph->imageWidth($path);
 
-        if (($ratio = $height / $width) > Telegraph::MAX_PHOTO_HEIGHT_WIDTH_RATIO || $ratio < (1 / Telegraph::MAX_PHOTO_HEIGHT_WIDTH_RATIO)) {
-            throw FileException::invalidPhotoRatio($ratio);
-        }
+            if (($totalLength = $height + $width) > Telegraph::MAX_PHOTO_HEIGHT_WIDTH_TOTAL) {
+                throw FileException::invalidPhotoSize($totalLength);
+            }
 
-        $telegraph->endpoint = self::ENDPOINT_SEND_PHOTO;
+            if (($ratio = $height / $width) > Telegraph::MAX_PHOTO_HEIGHT_WIDTH_RATIO || $ratio < (1 / Telegraph::MAX_PHOTO_HEIGHT_WIDTH_RATIO)) {
+                throw FileException::invalidPhotoRatio($ratio);
+            }
 
-        $telegraph->data['chat_id'] = $telegraph->getChat()->chat_id;
+            $telegraph->files->put('photo', new Attachment($path, $filename));
+
+            return $telegraph;
+        }
 
-        $telegraph->files->put('photo', new Attachment($path, $filename));
+        $telegraph->data['photo'] = $path;
 
         return $telegraph;
     }
diff --git a/src/DTO/Attachment.php b/src/DTO/Attachment.php
index ba89ce97..f23ba246 100644
--- a/src/DTO/Attachment.php
+++ b/src/DTO/Attachment.php
@@ -4,6 +4,7 @@ namespace DefStudio\Telegraph\DTO;
 
 use Illuminate\Contracts\Support\Arrayable;
 use Illuminate\Support\Facades\File;
+use Illuminate\Support\Str;
 
 class Attachment implements Arrayable
 {
@@ -18,6 +19,11 @@ class Attachment implements Arrayable
         return $this->path;
     }
 
+    public function local(): bool
+    {
+        return Str::of($this->path)->startsWith('/');
+    }
+
     public function contents(): string
     {
         return File::get($this->path);


Test patch:
diff --git a/tests/Unit/Concerns/SendsAttachmentsTest.php b/tests/Unit/Concerns/SendsAttachmentsTest.php
index 3b6741a8..4bda2652 100644
--- a/tests/Unit/Concerns/SendsAttachmentsTest.php
+++ b/tests/Unit/Concerns/SendsAttachmentsTest.php
@@ -73,12 +73,6 @@ test('documents are validated', function (string $path, bool $valid, string $exc
         'file' => 'valid_document.txt',
         'valid' => true,
     ],
-    'not found' => [
-        'file' => 'fake.txt',
-        'valid' => false,
-        'exception' => FileException::class,
-        'message' => 'not found',
-    ],
     'invalid size' => [
         'file' => 'invalid_document_size.txt',
         'valid' => false,
@@ -108,12 +102,6 @@ test('thumbnails are validated', function (string $thumbnailPath, bool $valid, s
         'file' => 'thumbnail.jpg',
         'valid' => true,
     ],
-    'not found' => [
-        'file' => 'fake.jpg',
-        'valid' => false,
-        'exception' => FileException::class,
-        'message' => 'not found',
-    ],
     'invalid size' => [
         'file' => 'invalid_thumbnail_size.jpg',
         'valid' => false,
@@ -204,12 +192,6 @@ test('photos are validated', function (string $path, bool $valid, string $except
         'file' => 'photo.jpg',
         'valid' => true,
     ],
-    'not found' => [
-        'file' => 'fake.jpg',
-        'valid' => false,
-        'exception' => FileException::class,
-        'message' => 'not found',
-    ],
     'invalid weight' => [
         'file' => 'invalid_photo_size.jpg',
         'valid' => false,
@@ -289,12 +271,6 @@ test('voices are validated', function (string $path, bool $valid, string $except
         'file' => 'voice.ogg',
         'valid' => true,
     ],
-    'not found' => [
-        'file' => 'fake.ogg',
-        'valid' => false,
-        'exception' => FileException::class,
-        'message' => 'not found',
-    ],
 ]);
 
 it('can edit a message caption', function () {
diff --git a/tests/Unit/Models/TelegraphChatTest.php b/tests/Unit/Models/TelegraphChatTest.php
index 00b8d95a..994a9b54 100644
--- a/tests/Unit/Models/TelegraphChatTest.php
+++ b/tests/Unit/Models/TelegraphChatTest.php
@@ -87,6 +87,30 @@ it('can send a document', function () {
    ]);
 });
 
+it('can send a document from remote url', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $chat->document('https://test.dev/document.pdf')->markdown('test')->send();
+
+    Telegraph::assertSentData(\DefStudio\Telegraph\Telegraph::ENDPOINT_SEND_DOCUMENT, [
+        'document' => 'https://test.dev/document.pdf',
+    ]);
+});
+
+it('can send a document from file_id', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $uuid = Str::uuid();
+
+    $chat->document($uuid)->markdown('test')->send();
+
+    Telegraph::assertSentData(\DefStudio\Telegraph\Telegraph::ENDPOINT_SEND_DOCUMENT, [
+        'document' => $uuid,
+    ]);
+});
+
 it('can send a photo', function () {
     Telegraph::fake();
     $chat = make_chat();
@@ -98,6 +122,30 @@ it('can send a photo', function () {
     ]);
 });
 
+it('can send a photo from remote url', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $chat->photo('https://test.dev/photo.jpg')->markdown('test')->send();
+
+    Telegraph::assertSentData(\DefStudio\Telegraph\Telegraph::ENDPOINT_SEND_PHOTO, [
+        'photo' => 'https://test.dev/photo.jpg',
+    ]);
+});
+
+it('can send a photo from file_id', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $uuid = Str::uuid();
+
+    $chat->photo($uuid)->markdown('test')->send();
+
+    Telegraph::assertSentData(\DefStudio\Telegraph\Telegraph::ENDPOINT_SEND_PHOTO, [
+        'photo' => $uuid,
+    ]);
+});
+
 it('can send a voice', function () {
     Telegraph::fake();
     $chat = make_chat();
@@ -109,6 +157,30 @@ it('can send a voice', function () {
     ]);
 });
 
+it('can send a voice from remote url', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $chat->voice('https://test.dev/voice.ogg')->markdown('test')->send();
+
+    Telegraph::assertSentData(\DefStudio\Telegraph\Telegraph::ENDPOINT_SEND_VOICE, [
+        'voice' => 'https://test.dev/voice.ogg',
+    ]);
+});
+
+it('can send a voice from file_id', function () {
+    Telegraph::fake();
+    $chat = make_chat();
+
+    $uuid = Str::uuid();
+
+    $chat->voice($uuid)->markdown('test')->send();
+
+    Telegraph::assertSentData(\DefStudio\Telegraph\Telegraph::ENDPOINT_SEND_VOICE, [
+        'voice' => $uuid,
+    ]);
+});
+
 it('can edit a message caption', function () {
     Telegraph::fake();
     $chat = make_chat();