diff --git a/README.md b/README.md index 5ce4417..f853fa0 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ - Coin Toss Bot - Commands Bot - Dad Joke Bot + - Document Finder Bot - Giphy Bot - Insult Bot - Invite Bot @@ -40,7 +41,7 @@ - Weather Bot - Wikipedia Bot - YoMomma Bot - - Youtube Bot + - YouTube Bot - Included Bot Packages: - Games Package - Jokester Package @@ -131,6 +132,7 @@ use RTippin\MessengerBots\Bots\ChuckNorrisBot; use RTippin\MessengerBots\Bots\CoinTossBot; use RTippin\MessengerBots\Bots\CommandsBot; use RTippin\MessengerBots\Bots\DadJokeBot; +use RTippin\MessengerBots\Bots\DocumentFinderBot; use RTippin\MessengerBots\Bots\GiphyBot; use RTippin\MessengerBots\Bots\InsultBot; use RTippin\MessengerBots\Bots\InviteBot; @@ -166,6 +168,7 @@ class MessengerServiceProvider extends ServiceProvider CoinTossBot::class, CommandsBot::class, DadJokeBot::class, + DocumentFinderBot::class, GiphyBot::class, InsultBot::class, InviteBot::class, diff --git a/assets/games_package_avatar.gif b/assets/games_package_avatar.gif new file mode 100644 index 0000000..8bed3e5 Binary files /dev/null and b/assets/games_package_avatar.gif differ diff --git a/assets/games_package_avatar.png b/assets/games_package_avatar.png deleted file mode 100644 index b86ff09..0000000 Binary files a/assets/games_package_avatar.png and /dev/null differ diff --git a/phpunit.xml b/phpunit.xml index edace43..5b1ae63 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -17,6 +17,7 @@ + \ No newline at end of file diff --git a/src/Bots/DocumentFinderBot.php b/src/Bots/DocumentFinderBot.php new file mode 100644 index 0000000..1ed4e42 --- /dev/null +++ b/src/Bots/DocumentFinderBot.php @@ -0,0 +1,121 @@ + 'document_finder', + 'description' => 'Search the group for uploaded documents. [ !document {search} ]', + 'name' => 'Document Finder', + 'unique' => true, + 'triggers' => ['!document', '!doc'], + 'match' => MessengerBots::MATCH_STARTS_WITH_CASELESS, + ]; + } + + /** + * @return array + */ + public function rules(): array + { + return [ + 'limit' => ['nullable', 'integer', 'min:1', 'max:10'], + ]; + } + + /** + * @throws Throwable + */ + public function handle(): void + { + $search = $this->getParsedMessage(); + + if (! is_null($search)) { + $documents = $this->searchDocuments($search); + + if (! $documents->count()) { + $this->sendNoResultsMessage($search); + + return; + } + + $this->sendDocumentResultsMessages($documents, $search); + + return; + } + + $this->sendInvalidSearchMessage(); + + $this->releaseCooldown(); + } + + /** + * @throws Throwable + */ + private function sendInvalidSearchMessage(): void + { + $this->composer()->emitTyping()->message('Please select a valid search term, i.e. ( !document resume )'); + } + + /** + * @throws Throwable + */ + private function sendNoResultsMessage(string $search): void + { + $this->composer()->emitTyping()->message("I didn't find any document(s) matching ( $search )"); + } + + /** + * @param Collection $documents + * @param string $search + * + * @throws Throwable + */ + private function sendDocumentResultsMessages(Collection $documents, string $search): void + { + Messenger::shouldUseAbsoluteRoutes(true); + + $this->composer()->emitTyping()->message("I found the following document(s) matching ( $search ) :"); + + $documents->each(fn (Message $document) => $this->sendDocumentMessage($document)); + } + + /** + * @param Message $document + * + * @throws Throwable + */ + private function sendDocumentMessage(Message $document): void + { + $this->composer()->message(":floppy_disk: $document->body - {$document->getDocumentDownloadRoute()}"); + } + + /** + * @param string $search + * @return Collection|Message[] + */ + private function searchDocuments(string $search): Collection + { + return $this->thread + ->documents() + ->latest() + ->where('body', 'LIKE', "%$search%") + ->limit($this->getPayload('limit') ?? 5) + ->get(); + } +} diff --git a/src/MessengerBotsServiceProvider.php b/src/MessengerBotsServiceProvider.php index 420189b..3807da4 100644 --- a/src/MessengerBotsServiceProvider.php +++ b/src/MessengerBotsServiceProvider.php @@ -8,6 +8,7 @@ use RTippin\MessengerBots\Bots\CoinTossBot; use RTippin\MessengerBots\Bots\CommandsBot; use RTippin\MessengerBots\Bots\DadJokeBot; +use RTippin\MessengerBots\Bots\DocumentFinderBot; use RTippin\MessengerBots\Bots\GiphyBot; use RTippin\MessengerBots\Bots\InsultBot; use RTippin\MessengerBots\Bots\InviteBot; @@ -39,6 +40,7 @@ class MessengerBotsServiceProvider extends ServiceProvider CoinTossBot::class, CommandsBot::class, DadJokeBot::class, + DocumentFinderBot::class, GiphyBot::class, InsultBot::class, InviteBot::class, diff --git a/src/Packages/GamesPackage.php b/src/Packages/GamesPackage.php index 7045ff6..45ba53a 100644 --- a/src/Packages/GamesPackage.php +++ b/src/Packages/GamesPackage.php @@ -20,7 +20,7 @@ public static function getSettings(): array 'alias' => 'games_package', 'description' => 'Bundles games you can play with the bot.', 'name' => 'Games', - 'avatar' => __DIR__.'/../../assets/games_package_avatar.png', + 'avatar' => __DIR__.'/../../assets/games_package_avatar.gif', ]; } diff --git a/src/Packages/NeoPackage.php b/src/Packages/NeoPackage.php index 2045e79..3f71c72 100644 --- a/src/Packages/NeoPackage.php +++ b/src/Packages/NeoPackage.php @@ -5,6 +5,7 @@ use RTippin\Messenger\MessengerBots; use RTippin\Messenger\Support\PackagedBot; use RTippin\MessengerBots\Bots\CommandsBot; +use RTippin\MessengerBots\Bots\DocumentFinderBot; use RTippin\MessengerBots\Bots\GiphyBot; use RTippin\MessengerBots\Bots\InviteBot; use RTippin\MessengerBots\Bots\KanyeBot; @@ -43,6 +44,10 @@ public static function installs(): array CommandsBot::class => [ 'cooldown' => 120, ], + DocumentFinderBot::class => [ + 'cooldown' => 15, + 'limit' => 10, + ], GiphyBot::class => [ 'cooldown' => 15, ], diff --git a/tests/Bots/DocumentFinderBotTest.php b/tests/Bots/DocumentFinderBotTest.php new file mode 100644 index 0000000..53d6e26 --- /dev/null +++ b/tests/Bots/DocumentFinderBotTest.php @@ -0,0 +1,256 @@ + 'document_finder', + 'description' => 'Search the group for uploaded documents. [ !document {search} ]', + 'name' => 'Document Finder', + 'unique' => true, + 'authorize' => false, + 'triggers' => ['!document', '!doc'], + 'match' => \RTippin\Messenger\MessengerBots::MATCH_STARTS_WITH_CASELESS, + ]; + + $this->assertSame($expected, MessengerBots::getHandlers(DocumentFinderBot::class)->toArray()); + } + + /** @test */ + public function it_sends_invalid_search_message() + { + $thread = $this->createGroupThread($this->tippin); + $message = Message::factory()->for($thread)->owner($this->tippin)->body('!doc')->create(); + $action = BotAction::factory()->for( + Bot::factory()->for($thread)->owner($this->tippin)->create() + )->owner($this->tippin)->create(); + $finder = MessengerBots::initializeHandler(DocumentFinderBot::class) + ->setDataForHandler($thread, $action, $message, '!doc'); + + $finder->handle(); + + $this->assertDatabaseHas('messages', [ + 'body' => 'Please select a valid search term, i.e. ( !document resume )', + ]); + $this->assertTrue($finder->shouldReleaseCooldown()); + } + + /** @test */ + public function it_sends_no_results_found_message() + { + $thread = $this->createGroupThread($this->tippin); + $message = Message::factory()->for($thread)->owner($this->tippin)->body('!doc unknown')->create(); + $action = BotAction::factory()->for( + Bot::factory()->for($thread)->owner($this->tippin)->create() + )->owner($this->tippin)->create(); + $finder = MessengerBots::initializeHandler(DocumentFinderBot::class) + ->setDataForHandler($thread, $action, $message, '!doc'); + + $finder->handle(); + + $this->assertDatabaseHas('messages', [ + 'body' => 'I didn\'t find any document(s) matching ( unknown )', + ]); + $this->assertFalse($finder->shouldReleaseCooldown()); + } + + /** @test */ + public function it_finds_single_result() + { + $thread = $this->createGroupThread($this->tippin); + $testPdf = Message::factory()->for($thread)->owner($this->tippin)->document()->body('testing.pdf')->create(); + $fooPdf = Message::factory()->for($thread)->owner($this->tippin)->document()->body('foo.pdf')->create(); + Message::factory()->for($thread)->owner($this->tippin)->body('!doc test')->create(); + $message = Message::factory()->for($thread)->owner($this->tippin)->body('!doc test')->create(); + $action = BotAction::factory()->for( + Bot::factory()->for($thread)->owner($this->tippin)->create() + )->owner($this->tippin)->create(); + $finder = MessengerBots::initializeHandler(DocumentFinderBot::class) + ->setDataForHandler($thread, $action, $message, '!doc'); + + $finder->handle(); + + $this->assertDatabaseHas('messages', [ + 'body' => 'I found the following document(s) matching ( test ) :', + ]); + $this->assertDatabaseHas('messages', [ + 'body' => ':floppy_disk: testing.pdf - '.$testPdf->getDocumentDownloadRoute(), + ]); + $this->assertDatabaseMissing('messages', [ + 'body' => ':floppy_disk: foo.pdf - '.$fooPdf->getDocumentDownloadRoute(), + ]); + $this->assertFalse($finder->shouldReleaseCooldown()); + } + + /** @test */ + public function it_finds_multiple_results() + { + $thread = $this->createGroupThread($this->tippin); + $testPdf = Message::factory()->for($thread)->owner($this->tippin)->document()->body('testing_foo.pdf')->create(); + $fooPdf = Message::factory()->for($thread)->owner($this->tippin)->document()->body('foo.pdf')->create(); + Message::factory()->for($thread)->owner($this->tippin)->body('!doc test')->create(); + $message = Message::factory()->for($thread)->owner($this->tippin)->body('!doc foo')->create(); + $action = BotAction::factory()->for( + Bot::factory()->for($thread)->owner($this->tippin)->create() + )->owner($this->tippin)->create(); + $finder = MessengerBots::initializeHandler(DocumentFinderBot::class) + ->setDataForHandler($thread, $action, $message, '!doc'); + + $finder->handle(); + + $this->assertDatabaseHas('messages', [ + 'body' => 'I found the following document(s) matching ( foo ) :', + ]); + $this->assertDatabaseHas('messages', [ + 'body' => ':floppy_disk: testing_foo.pdf - '.$testPdf->getDocumentDownloadRoute(), + ]); + $this->assertDatabaseHas('messages', [ + 'body' => ':floppy_disk: foo.pdf - '.$fooPdf->getDocumentDownloadRoute(), + ]); + $this->assertFalse($finder->shouldReleaseCooldown()); + } + + /** @test */ + public function it_fires_events() + { + BaseMessengerAction::enableEvents(); + $thread = $this->createGroupThread($this->tippin); + $message = Message::factory()->for($thread)->owner($this->tippin)->body('!doc unknown')->create(); + $action = BotAction::factory()->for( + Bot::factory()->for($thread)->owner($this->tippin)->create() + )->owner($this->tippin)->create(); + Event::fake([ + NewMessageBroadcast::class, + NewMessageEvent::class, + Typing::class, + ]); + + MessengerBots::initializeHandler(DocumentFinderBot::class) + ->setDataForHandler($thread, $action, $message, '!doc') + ->handle(); + + Event::assertDispatched(NewMessageBroadcast::class); + Event::assertDispatched(NewMessageEvent::class); + Event::assertDispatched(Typing::class); + } + + /** @test */ + public function it_can_be_attached_to_a_bot_handler() + { + $thread = $this->createGroupThread($this->tippin); + $bot = Bot::factory()->for($thread)->owner($this->tippin)->create(); + $this->actingAs($this->tippin); + + $this->postJson(route('api.messenger.threads.bots.actions.store', [ + 'thread' => $thread->id, + 'bot' => $bot->id, + ]), [ + 'handler' => 'document_finder', + 'cooldown' => 0, + 'admin_only' => false, + 'enabled' => true, + 'limit' => 5, + ]) + ->assertSuccessful() + ->assertJson([ + 'payload' => [ + 'limit' => 5, + ], + ]); + } + + /** + * @test + * @dataProvider passesLimitValidation + * + * @param $limit + */ + public function it_passes_validation_attaching_to_a_bot_handler($limit) + { + $thread = $this->createGroupThread($this->tippin); + $bot = Bot::factory()->for($thread)->owner($this->tippin)->create(); + $this->actingAs($this->tippin); + + $this->postJson(route('api.messenger.threads.bots.actions.store', [ + 'thread' => $thread->id, + 'bot' => $bot->id, + ]), [ + 'handler' => 'document_finder', + 'cooldown' => 0, + 'admin_only' => false, + 'enabled' => true, + 'limit' => $limit, + ]) + ->assertSuccessful(); + } + + /** + * @test + * @dataProvider failLimitValidation + * + * @param $limit + */ + public function it_fails_validation_attaching_to_a_bot_handler($limit) + { + $thread = $this->createGroupThread($this->tippin); + $bot = Bot::factory()->for($thread)->owner($this->tippin)->create(); + $this->actingAs($this->tippin); + + $this->postJson(route('api.messenger.threads.bots.actions.store', [ + 'thread' => $thread->id, + 'bot' => $bot->id, + ]), [ + 'handler' => 'document_finder', + 'cooldown' => 0, + 'admin_only' => false, + 'enabled' => true, + 'limit' => $limit, + ]) + ->assertStatus(422) + ->assertJsonValidationErrors('limit'); + } + + public function passesLimitValidation(): array + { + return [ + 'Nullable' => [null], + 'Min' => [1], + 'Max' => [10], + ]; + } + + public function failLimitValidation(): array + { + return [ + 'Boolean' => [false], + 'Array' => [[1, 2]], + 'Under minimum' => [0], + 'Negative' => [-1], + 'Over maximum' => [11], + 'String' => ['Nope'], + ]; + } +} diff --git a/tests/Packages/GamesPackageTest.php b/tests/Packages/GamesPackageTest.php index 9102b6a..679466f 100644 --- a/tests/Packages/GamesPackageTest.php +++ b/tests/Packages/GamesPackageTest.php @@ -18,6 +18,12 @@ protected function setUp(): void MessengerBots::registerPackagedBots([GamesPackage::class]); } + /** @test */ + public function it_is_registered() + { + $this->assertTrue(MessengerBots::isValidPackagedBot(GamesPackage::class)); + } + /** @test */ public function it_gets_formatted_settings() { @@ -26,18 +32,22 @@ public function it_gets_formatted_settings() 'name' => 'Games', 'description' => 'Bundles games you can play with the bot.', 'avatar' => [ - 'sm' => '/messenger/assets/bot-package/sm/games_package/avatar.png', - 'md' => '/messenger/assets/bot-package/md/games_package/avatar.png', - 'lg' => '/messenger/assets/bot-package/lg/games_package/avatar.png', - ], - 'installs' => [ - MessengerBots::getHandlers(CoinTossBot::class)->toArray(), - MessengerBots::getHandlers(RockPaperScissorsBot::class)->toArray(), - MessengerBots::getHandlers(RollBot::class)->toArray(), + 'sm' => '/messenger/assets/bot-package/sm/games_package/avatar.gif', + 'md' => '/messenger/assets/bot-package/md/games_package/avatar.gif', + 'lg' => '/messenger/assets/bot-package/lg/games_package/avatar.gif', ], + 'installs' => [], + 'already_installed' => [], + ]; + $installs = [ + MessengerBots::getHandlers(CoinTossBot::class)->toArray(), + MessengerBots::getHandlers(RockPaperScissorsBot::class)->toArray(), + MessengerBots::getHandlers(RollBot::class)->toArray(), ]; + $package = MessengerBots::getPackagedBots(GamesPackage::class); - $this->assertSame($expected, MessengerBots::getPackagedBots(GamesPackage::class)->toArray()); + $this->assertSame($expected, $package->toArray()); + $this->assertSame($installs, $package->installs->toArray()); } /** @test */ diff --git a/tests/Packages/JokesterPackageTest.php b/tests/Packages/JokesterPackageTest.php index b2fe52c..ee385f5 100644 --- a/tests/Packages/JokesterPackageTest.php +++ b/tests/Packages/JokesterPackageTest.php @@ -22,6 +22,12 @@ protected function setUp(): void MessengerBots::registerPackagedBots([JokesterPackage::class]); } + /** @test */ + public function it_is_registered() + { + $this->assertTrue(MessengerBots::isValidPackagedBot(JokesterPackage::class)); + } + /** @test */ public function it_gets_formatted_settings() { @@ -34,18 +40,22 @@ public function it_gets_formatted_settings() 'md' => '/messenger/assets/bot-package/md/jokester_package/avatar.jpg', 'lg' => '/messenger/assets/bot-package/lg/jokester_package/avatar.jpg', ], - 'installs' => [ - MessengerBots::getHandlers(ChuckNorrisBot::class)->toArray(), - MessengerBots::getHandlers(DadJokeBot::class)->toArray(), - MessengerBots::getHandlers(InsultBot::class)->toArray(), - MessengerBots::getHandlers(JokeBot::class)->toArray(), - MessengerBots::getHandlers(KnockBot::class)->toArray(), - MessengerBots::getHandlers(ReactionBot::class)->toArray(), - MessengerBots::getHandlers(YoMommaBot::class)->toArray(), - ], + 'installs' => [], + 'already_installed' => [], + ]; + $installs = [ + MessengerBots::getHandlers(ChuckNorrisBot::class)->toArray(), + MessengerBots::getHandlers(DadJokeBot::class)->toArray(), + MessengerBots::getHandlers(InsultBot::class)->toArray(), + MessengerBots::getHandlers(JokeBot::class)->toArray(), + MessengerBots::getHandlers(KnockBot::class)->toArray(), + MessengerBots::getHandlers(ReactionBot::class)->toArray(), + MessengerBots::getHandlers(YoMommaBot::class)->toArray(), ]; + $package = MessengerBots::getPackagedBots(JokesterPackage::class); - $this->assertSame($expected, MessengerBots::getPackagedBots(JokesterPackage::class)->toArray()); + $this->assertSame($expected, $package->toArray()); + $this->assertSame($installs, $package->installs->toArray()); } /** @test */ diff --git a/tests/Packages/NeoPackageTest.php b/tests/Packages/NeoPackageTest.php index 8c16dbc..0a3be3c 100644 --- a/tests/Packages/NeoPackageTest.php +++ b/tests/Packages/NeoPackageTest.php @@ -4,6 +4,7 @@ use RTippin\Messenger\Facades\MessengerBots; use RTippin\MessengerBots\Bots\CommandsBot; +use RTippin\MessengerBots\Bots\DocumentFinderBot; use RTippin\MessengerBots\Bots\GiphyBot; use RTippin\MessengerBots\Bots\InviteBot; use RTippin\MessengerBots\Bots\KanyeBot; @@ -25,6 +26,12 @@ protected function setUp(): void MessengerBots::registerPackagedBots([NeoPackage::class]); } + /** @test */ + public function it_is_registered() + { + $this->assertTrue(MessengerBots::isValidPackagedBot(NeoPackage::class)); + } + /** @test */ public function it_gets_formatted_settings() { @@ -37,21 +44,26 @@ public function it_gets_formatted_settings() 'md' => '/messenger/assets/bot-package/md/neo_package/avatar.jpg', 'lg' => '/messenger/assets/bot-package/lg/neo_package/avatar.jpg', ], - 'installs' => [ - MessengerBots::getHandlers(GiphyBot::class)->toArray(), - MessengerBots::getHandlers(InviteBot::class)->toArray(), - MessengerBots::getHandlers(KanyeBot::class)->toArray(), - MessengerBots::getHandlers(CommandsBot::class)->toArray(), - MessengerBots::getHandlers(LocationBot::class)->toArray(), - MessengerBots::getHandlers(QuotableBot::class)->toArray(), - MessengerBots::getHandlers(RandomImageBot::class)->toArray(), - MessengerBots::getHandlers(WeatherBot::class)->toArray(), - MessengerBots::getHandlers(WikiBot::class)->toArray(), - MessengerBots::getHandlers(YoutubeBot::class)->toArray(), - ], + 'installs' => [], + 'already_installed' => [], + ]; + $installs = [ + MessengerBots::getHandlers(CommandsBot::class)->toArray(), + MessengerBots::getHandlers(DocumentFinderBot::class)->toArray(), + MessengerBots::getHandlers(GiphyBot::class)->toArray(), + MessengerBots::getHandlers(InviteBot::class)->toArray(), + MessengerBots::getHandlers(KanyeBot::class)->toArray(), + MessengerBots::getHandlers(LocationBot::class)->toArray(), + MessengerBots::getHandlers(QuotableBot::class)->toArray(), + MessengerBots::getHandlers(RandomImageBot::class)->toArray(), + MessengerBots::getHandlers(WeatherBot::class)->toArray(), + MessengerBots::getHandlers(WikiBot::class)->toArray(), + MessengerBots::getHandlers(YoutubeBot::class)->toArray(), ]; + $package = MessengerBots::getPackagedBots(NeoPackage::class); - $this->assertSame($expected, MessengerBots::getPackagedBots(NeoPackage::class)->toArray()); + $this->assertSame($expected, $package->toArray()); + $this->assertSame($installs, $package->installs->toArray()); } /** @test */ @@ -67,7 +79,7 @@ public function it_can_be_installed() ]) ->assertSuccessful() ->assertJson([ - 'actions_count' => 10, + 'actions_count' => 11, ]); } }