diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/Discord/CHANGELOG.md index 91b7e5fb62ef8..5f0d8dd96e02e 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/CHANGELOG.md +++ b/src/Symfony/Component/Notifier/Bridge/Discord/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.2 +--- + + * Check embed limitations + 5.3 --- diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordAuthorEmbedObject.php b/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordAuthorEmbedObject.php index 7dfb1cc1befc5..590fd721f1f57 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordAuthorEmbedObject.php +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordAuthorEmbedObject.php @@ -11,16 +11,24 @@ namespace Symfony\Component\Notifier\Bridge\Discord\Embeds; +use Symfony\Component\Notifier\Exception\LengthException; + /** * @author Karoly Gossler */ final class DiscordAuthorEmbedObject extends AbstractDiscordEmbedObject { + private const NAME_LIMIT = 256; + /** * @return $this */ public function name(string $name): static { + if (\strlen($name) > self::NAME_LIMIT) { + throw new LengthException(sprintf('Maximum length for the name is %d characters.', self::NAME_LIMIT)); + } + $this->options['name'] = $name; return $this; diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordEmbed.php b/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordEmbed.php index 286e5ebc242e8..f6c54608df4a6 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordEmbed.php +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordEmbed.php @@ -11,16 +11,26 @@ namespace Symfony\Component\Notifier\Bridge\Discord\Embeds; +use Symfony\Component\Notifier\Exception\LengthException; + /** * @author Karoly Gossler */ final class DiscordEmbed extends AbstractDiscordEmbed { + private const TITLE_LIMIT = 256; + private const DESCRIPTION_LIMIT = 4096; + private const FIELDS_LIMIT = 25; + /** * @return $this */ public function title(string $title): static { + if (\strlen($title) > self::TITLE_LIMIT) { + throw new LengthException(sprintf('Maximum length for the title is %d characters.', self::TITLE_LIMIT)); + } + $this->options['title'] = $title; return $this; @@ -31,6 +41,10 @@ public function title(string $title): static */ public function description(string $description): static { + if (\strlen($description) > self::DESCRIPTION_LIMIT) { + throw new LengthException(sprintf('Maximum length for the description is %d characters.', self::DESCRIPTION_LIMIT)); + } + $this->options['description'] = $description; return $this; @@ -111,6 +125,10 @@ public function author(DiscordAuthorEmbedObject $author): static */ public function addField(DiscordFieldEmbedObject $field): static { + if (self::FIELDS_LIMIT === \count($this->options['fields'] ?? [])) { + throw new LengthException(sprintf('Maximum number of fields should not exceed %d.', self::FIELDS_LIMIT)); + } + if (!isset($this->options['fields'])) { $this->options['fields'] = []; } diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordFieldEmbedObject.php b/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordFieldEmbedObject.php index 79f8bca808f98..07b2e651d3dbd 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordFieldEmbedObject.php +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordFieldEmbedObject.php @@ -11,16 +11,25 @@ namespace Symfony\Component\Notifier\Bridge\Discord\Embeds; +use Symfony\Component\Notifier\Exception\LengthException; + /** * @author Karoly Gossler */ final class DiscordFieldEmbedObject extends AbstractDiscordEmbedObject { + private const NAME_LIMIT = 256; + private const VALUE_LIMIT = 1024; + /** * @return $this */ public function name(string $name): static { + if (\strlen($name) > self::NAME_LIMIT) { + throw new LengthException(sprintf('Maximum length for the name is %d characters.', self::NAME_LIMIT)); + } + $this->options['name'] = $name; return $this; @@ -31,6 +40,10 @@ public function name(string $name): static */ public function value(string $value): static { + if (\strlen($value) > self::VALUE_LIMIT) { + throw new LengthException(sprintf('Maximum length for the value is %d characters.', self::VALUE_LIMIT)); + } + $this->options['value'] = $value; return $this; diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordFooterEmbedObject.php b/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordFooterEmbedObject.php index 62d2579a0ecaf..710b1d20b32bb 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordFooterEmbedObject.php +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Embeds/DiscordFooterEmbedObject.php @@ -11,16 +11,24 @@ namespace Symfony\Component\Notifier\Bridge\Discord\Embeds; +use Symfony\Component\Notifier\Exception\LengthException; + /** * @author Karoly Gossler */ final class DiscordFooterEmbedObject extends AbstractDiscordEmbedObject { + private const TEXT_LIMIT = 2048; + /** * @return $this */ public function text(string $text): static { + if (\strlen($text) > self::TEXT_LIMIT) { + throw new LengthException(sprintf('Maximum length for the text is %d characters.', self::TEXT_LIMIT)); + } + $this->options['text'] = $text; return $this; diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordAuthorEmbedObjectTest.php b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordAuthorEmbedObjectTest.php new file mode 100644 index 0000000000000..1fa525505d909 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordAuthorEmbedObjectTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Discord\Tests\Embeds; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordAuthorEmbedObject; +use Symfony\Component\Notifier\Exception\LengthException; + +final class DiscordAuthorEmbedObjectTest extends TestCase +{ + public function testCanBeInstantiated() + { + $author = (new DiscordAuthorEmbedObject()) + ->name('Doe') + ->url('http://ur.l') + ->iconUrl('http://icon-ur.l') + ->proxyIconUrl('http://proxy-icon-ur.l'); + + $this->assertSame([ + 'name' => 'Doe', + 'url' => 'http://ur.l', + 'icon_url' => 'http://icon-ur.l', + 'proxy_icon_url' => 'http://proxy-icon-ur.l', + ], $author->toArray()); + } + + public function testThrowsWhenNameExceedsCharacterLimit() + { + $this->expectException(LengthException::class); + $this->expectExceptionMessage('Maximum length for the name is 256 characters.'); + + (new DiscordAuthorEmbedObject())->name(str_repeat('h', 257)); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordEmbedTest.php b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordEmbedTest.php new file mode 100644 index 0000000000000..02fdd40b5d64a --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordEmbedTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Discord\Tests\Embeds; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordEmbed; +use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordFieldEmbedObject; +use Symfony\Component\Notifier\Exception\LengthException; + +final class DiscordEmbedTest extends TestCase +{ + public function testCanBeInstantiated() + { + $embed = (new DiscordEmbed()) + ->title('foo') + ->description('bar') + ->addField((new DiscordFieldEmbedObject()) + ->name('baz') + ->value('qux') + ); + + $this->assertSame([ + 'title' => 'foo', + 'description' => 'bar', + 'fields' => [ + [ + 'name' => 'baz', + 'value' => 'qux', + ], + ], + ], $embed->toArray()); + } + + public function testThrowsWhenTitleExceedsCharacterLimit() + { + $this->expectException(LengthException::class); + $this->expectExceptionMessage('Maximum length for the title is 256 characters.'); + + (new DiscordEmbed())->title(str_repeat('h', 257)); + } + + public function testThrowsWhenDescriptionExceedsCharacterLimit() + { + $this->expectException(LengthException::class); + $this->expectExceptionMessage('Maximum length for the description is 4096 characters.'); + + (new DiscordEmbed())->description(str_repeat('h', 4097)); + } + + public function testThrowsWhenFieldsLimitReached() + { + $embed = new DiscordEmbed(); + for ($i = 0; $i < 25; ++$i) { + $embed->addField((new DiscordFieldEmbedObject()) + ->name('baz') + ->value('qux') + ); + } + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Maximum number of fields should not exceed 25.'); + + $embed->addField((new DiscordFieldEmbedObject()) + ->name('fail') + ->value('fail') + ); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordFieldEmbedObjectTest.php b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordFieldEmbedObjectTest.php new file mode 100644 index 0000000000000..c432aab995385 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordFieldEmbedObjectTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Discord\Tests\Embeds; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordFieldEmbedObject; +use Symfony\Component\Notifier\Exception\LengthException; + +final class DiscordFieldEmbedObjectTest extends TestCase +{ + public function testCanBeInstantiated() + { + $field = (new DiscordFieldEmbedObject()) + ->name('foo') + ->value('bar') + ->inline(true); + + $this->assertSame([ + 'name' => 'foo', + 'value' => 'bar', + 'inline' => true, + ], $field->toArray()); + } + + public function testThrowsWhenNameExceedsCharacterLimit() + { + $this->expectException(LengthException::class); + $this->expectExceptionMessage('Maximum length for the name is 256 characters.'); + + (new DiscordFieldEmbedObject())->name(str_repeat('h', 257)); + } + + public function testThrowsWhenValueExceedsCharacterLimit() + { + $this->expectException(LengthException::class); + $this->expectExceptionMessage('Maximum length for the value is 1024 characters.'); + + (new DiscordFieldEmbedObject())->value(str_repeat('h', 1025)); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordFooterEmbedObjectTest.php b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordFooterEmbedObjectTest.php new file mode 100644 index 0000000000000..c9d50a46b89d2 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/Embeds/DiscordFooterEmbedObjectTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Discord\Tests\Embeds; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Discord\Embeds\DiscordFooterEmbedObject; +use Symfony\Component\Notifier\Exception\LengthException; + +final class DiscordFooterEmbedObjectTest extends TestCase +{ + public function testCanBeInstantiated() + { + $author = (new DiscordFooterEmbedObject()) + ->text('foo') + ->iconUrl('http://icon-ur.l') + ->proxyIconUrl('http://proxy-icon-ur.l'); + + $this->assertSame([ + 'text' => 'foo', + 'icon_url' => 'http://icon-ur.l', + 'proxy_icon_url' => 'http://proxy-icon-ur.l', + ], $author->toArray()); + } + + public function testThrowsWhenTextExceedsCharacterLimit() + { + $this->expectException(LengthException::class); + $this->expectExceptionMessage('Maximum length for the text is 2048 characters.'); + + (new DiscordFooterEmbedObject())->text(str_repeat('h', 2049)); + } +}