diff --git a/composer.json b/composer.json index 71a81fd..5c7e4f8 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "symfony/form": ">=7.1.5", "symfony/framework-bundle": ">=7.1.5", "symfony/http-client": ">=7.1.5", + "symfony/mime": "7.1.*", "symfony/monolog-bundle": "^3.10", "symfony/runtime": ">=7.1.1", "symfony/twig-bundle": ">=7.1.5", diff --git a/composer.lock b/composer.lock index c58bb60..421b758 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5be6db080cb40b3dcbdb7342ad36e6a6", + "content-hash": "2afff3ef65d6c29ae77e5e8f8ad3bb92", "packages": [ { "name": "adam-paterson/oauth2-slack", @@ -4056,6 +4056,90 @@ ], "time": "2024-11-13T14:25:32+00:00" }, + { + "name": "symfony/mime", + "version": "v7.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "caa1e521edb2650b8470918dfe51708c237f0598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/caa1e521edb2650b8470918dfe51708c237f0598", + "reference": "caa1e521edb2650b8470918dfe51708c237f0598", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.1.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-25T15:11:02+00:00" + }, { "name": "symfony/monolog-bridge", "version": "v7.1.1", @@ -4516,6 +4600,89 @@ ], "time": "2024-09-09T11:45:10+00:00" }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "symfony/polyfill-intl-normalizer", "version": "v1.31.0", diff --git a/src/Discord/ApiHelper.php b/src/Discord/ApiHelper.php index 446b75c..b8ac89e 100644 --- a/src/Discord/ApiHelper.php +++ b/src/Discord/ApiHelper.php @@ -12,6 +12,8 @@ namespace JoliCode\SecretSanta\Discord; use JoliCode\SecretSanta\Model\File; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; @@ -56,7 +58,7 @@ public function getRolesInGuild(int $guildId): array return $response->toArray(); } - public function sendMessage(int $userId, string $message): void + public function sendMessage(int $userId, string $message, ?File $file = null): void { // Create a private channel with the user $response = $this->callApi('POST', '/users/@me/channels', [ @@ -72,14 +74,31 @@ public function sendMessage(int $userId, string $message): void $channel = $response->toArray(); $channelId = $channel['id']; + $body = []; + $payload = [ + 'content' => $message, + ]; + + if ($file) { + $payload['attachements'][] = [ + 'id' => 0, + 'description' => 'Secret Santa spoiling code', + 'filename' => $file->name, + ]; + $body['files[0]'] = new DataPart($file->content, $file->name, 'text/plain'); + } + + $body['payload_json'] = new DataPart(json_encode($payload), null, 'application/json'); + + $formData = new FormDataPart($body); + $options = [ - 'json' => [ - 'content' => $message - ], + 'body' => $formData->bodyToString(), + 'headers' => $formData->getPreparedHeaders()->toArray(), ]; // Send message to the private channel - $response = $this->callApi('POST', "/channels/$channelId/messages", $options); + $response = $this->callApi('POST', "/channels/{$channelId}/messages", $options); if (200 !== $response->getStatusCode()) { throw new \RuntimeException('Failed to send private message: ' . $response->getContent(false)); diff --git a/src/Discord/MessageSender.php b/src/Discord/MessageSender.php index 4735064..24b7608 100644 --- a/src/Discord/MessageSender.php +++ b/src/Discord/MessageSender.php @@ -12,6 +12,7 @@ namespace JoliCode\SecretSanta\Discord; use JoliCode\SecretSanta\Exception\MessageSendFailedException; +use JoliCode\SecretSanta\Model\File; use JoliCode\SecretSanta\Model\SecretSanta; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; @@ -96,19 +97,17 @@ public function sendAdminMessage(SecretSanta $secretSanta, string $code, string In case of trouble or if you need it for whatever reason, here is a way to **retrieve the secret repartition**: -- Copy the following content: -```%s``` +- Copy the content of the `secret-santa-spoil-code.txt` file attached to this message - Paste the content on <%s> then submit Remember, with great power comes great responsibility! Happy Secret Santa!', - $code, $spoilUrl ); try { - $this->apiHelper->sendMessage((int) $secretSanta->getConfig()->getAdmin()->getIdentifier(), $text); + $this->apiHelper->sendMessage((int) $secretSanta->getConfig()->getAdmin()->getIdentifier(), $text, new File('secret-santa-spoil-code.txt', $code)); } catch (ClientExceptionInterface $e) { $precision = null; diff --git a/src/Model/File.php b/src/Model/File.php new file mode 100644 index 0000000..7db5cac --- /dev/null +++ b/src/Model/File.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace JoliCode\SecretSanta\Model; + +readonly class File +{ + public function __construct( + public string $name, + public string $content, + ) { + } +}