]> git.localhorst.tv Git - alttp.git/commitdiff
discord result command
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 1 May 2022 13:04:30 +0000 (15:04 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 1 May 2022 13:04:30 +0000 (15:04 +0200)
app/DiscordBotCommands/BaseCommand.php [new file with mode: 0644]
app/DiscordBotCommands/PresenceCommand.php [new file with mode: 0644]
app/DiscordBotCommands/ResultCommand.php [new file with mode: 0644]
app/Models/DiscordBotCommand.php
app/Models/Result.php
app/Models/User.php
lang/de/discord_commands.php [new file with mode: 0644]
lang/en/discord_commands.php [new file with mode: 0644]

diff --git a/app/DiscordBotCommands/BaseCommand.php b/app/DiscordBotCommands/BaseCommand.php
new file mode 100644 (file)
index 0000000..eb3a012
--- /dev/null
@@ -0,0 +1,126 @@
+<?php
+
+namespace App\DiscordBotCommands;
+
+use App\Models\DiscordBotCommand;
+use App\Models\Round;
+use App\Models\User;
+use Discord\Discord;
+use Discord\Parts\Channel\Channel;
+use Discord\Parts\Guild\Guild;
+use Discord\Parts\User\Member;
+use Illuminate\Support\Facades\App;
+
+abstract class BaseCommand {
+
+       public static function resolve(Discord $discord, DiscordBotCommand $cmd) {
+               switch ($cmd->command) {
+                       case 'presence':
+                               return new PresenceCommand($discord, $cmd);
+                       case 'result':
+                               return new ResultCommand($discord, $cmd);
+                       default:
+                               throw new Exception('unrecognized command');
+               }
+       }
+
+       public abstract function execute();
+
+
+       protected function __construct(Discord $discord, DiscordBotCommand $cmd) {
+               $this->discord = $discord;
+               $this->command = $cmd;
+       }
+
+       protected function fetchGuild() {
+               if (isset($this->guild)) {
+                       return \React\Promise\resolve($this->guild);
+               }
+               return $this->discord->guilds
+                       ->fetch($this->command->tournament->discord)
+                       ->then(function (Guild $guild) {
+                               $this->guild = $guild;
+                               if ($guild->preferred_locale) {
+                                       App::setLocale($guild->preferred_locale);
+                               }
+                               return $guild;
+                       });
+       }
+
+       protected function fetchMember() {
+               return $this->fetchGuild()->then(function (Guild $guild) {
+                       return $guild->members
+                               ->fetch($this->getParameter('user'))
+                               ->then(function (Member $member) {
+                                       $this->member = $member;
+                                       return $member;
+                               });
+               });
+       }
+
+       protected function fetchRoundChannel() {
+               if (isset($this->roundChannel)) {
+                       return \React\Promise\resolve($this->roundChannel);
+               }
+               return $this->fetchGuild()
+                       ->then(function (Guild $guild) {
+                               $channel = $guild->channels->find(function (Channel $c) {
+                                       return $c->name == $this->getRoundChannelName();
+                               });
+                               if ($channel) {
+                                       return $channel;
+                               }
+                               $channel = $guild->channels->create([
+                                       'name' => $this->getRoundChannelName(),
+                                       'is_private' => true,
+                                       'parent_id' => $this->command->tournament->discord_round_category,
+                               ]);
+                               return $guild->channels->save($channel);
+                       })
+                       ->then(function (Channel $channel) {
+                               $this->roundChannel = $channel;
+                               return $channel;
+                       });
+       }
+
+
+       protected function getParameter($name) {
+               return $this->command->parameters[$name];
+       }
+
+       protected function getRound() {
+               if (!$this->hasParameter('round')) {
+                       throw new \Exception('no rounds in parameters');
+               }
+               return Round::findOrFail($this->getParameter('round'));
+       }
+
+       protected function getRoundChannelName() {
+               $round = $this->getRound();
+               return sprintf($this->command->tournament->discord_round_template, $round->number);
+       }
+
+       protected function getUser() {
+               if (!$this->hasParameter('user')) {
+                       throw new \Exception('no user in parameters');
+               }
+               return User::findOrFail($this->getParameter('user'));
+       }
+
+       protected function hasParameter($name) {
+               return array_key_exists($name, $this->command->parameters);
+       }
+
+       protected function hasRoundChannels() {
+               return !empty($this->command->tournament->discord_round_template);
+       }
+
+
+       protected $command;
+       protected $discord;
+
+       protected $guild = null;
+       protected $member = null;
+       protected $roundChannel = null;
+
+}
diff --git a/app/DiscordBotCommands/PresenceCommand.php b/app/DiscordBotCommands/PresenceCommand.php
new file mode 100644 (file)
index 0000000..c466b1c
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+namespace App\DiscordBotCommands;
+
+use App\Models\DiscordBotCommand;
+use Discord\Discord;
+use Discord\Parts\User\Activity;
+use React\Promise\Promise;
+
+class PresenceCommand extends BaseCommand {
+
+       public function __construct(Discord $discord, DiscordBotCommand $cmd) {
+               parent::__construct($discord, $cmd);
+       }
+
+       public function execute() {
+               return new Promise(function($resolve) {
+                       $activity = null;
+                       $idle = false;
+                       $status = 'online';
+                       $afk = false;
+                       if ($this->hasParameter('activity')) {
+                               $activity = new Activity($this->discord);
+                               $activity->type = $this->getParameter('activity');
+                               if ($this->hasParameter('name')) {
+                                       $activity->name = $this->getParameter('name');
+                               }
+                               if ($this->hasParameter('url')) {
+                                       $activity->url = $this->getParameter('url');
+                               }
+                       }
+                       if ($this->hasParameter('idle')) {
+                               $idle = $this->parameters['idle'];
+                       }
+                       if ($this->hasParameter('status')) {
+                               $status = $this->getParameter('status');
+                       }
+                       if ($this->hasParameter('afk')) {
+                               $afk = $this->getParameter('afk');
+                       }
+                       $this->discord->updatePresence($activity, $idle, $status, $afk);
+                       $resolve();
+               });
+       }
+
+}
diff --git a/app/DiscordBotCommands/ResultCommand.php b/app/DiscordBotCommands/ResultCommand.php
new file mode 100644 (file)
index 0000000..bfe35bd
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+namespace App\DiscordBotCommands;
+
+use App\Models\DiscordBotCommand;
+use Discord\Discord;
+use Discord\Parts\Channel\Channel;
+use Discord\Parts\Channel\Message;
+use Discord\Parts\User\Member;
+
+class ResultCommand extends BaseCommand {
+
+       public function __construct(Discord $discord, DiscordBotCommand $cmd) {
+               parent::__construct($discord, $cmd);
+       }
+
+       public function execute() {
+               if (!$this->hasRoundChannels()) {
+                       return \React\Promise\resolve();
+               }
+               return $this->fetchRoundChannel()
+                       ->then(function (Channel $channel) {
+                               return $this->fetchMember();
+                       })
+                       ->then(function (Member $member) {
+                               return $this->roundChannel->setPermissions($member, [
+                                       'view_channel',
+                               ]);
+                       })
+                       ->then(function () {
+                               $user = $this->getUser();
+                               $round = $this->getRound();
+                               $result = $user->findResult($round);
+                               $msg = '';
+                               if (!$result || $result->forfeit) {
+                                       $msg = __('discord_commands.result.forfeit', ['name' => $user->getName()]);
+                               } else {
+                                       $msg = __('discord_commands.result.finish', ['name' => $user->getName(), 'time' => $result->formatTime()]);
+                               }
+                               return $this->roundChannel->sendMessage($msg);
+                       });
+       }
+
+}
index aec2f56988997ec01f666fbacfbd659a55aa46f7..8a74d4342e11046c7c56f5fd41ea38a43810e229 100644 (file)
@@ -2,8 +2,10 @@
 
 namespace App\Models;
 
+use App\DiscordBotCommands\BaseCommand;
 use Discord\Discord;
-use Discord\Parts\User\Activity;
+use Discord\Parts\Channel\Channel;
+use Discord\Parts\Guild\Guild;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
@@ -11,58 +13,55 @@ class DiscordBotCommand extends Model
 {
        use HasFactory;
 
+       public function tournament() {
+               return $this->belongsTo(Tournament::class);
+       }
+
+       public function user() {
+               return $this->belongsTo(User::class);
+       }
+
        public function execute(Discord $discord) {
-               $this->status = 'executing';
-               $this->executed_at = now();
-               $this->save();
+               $this->setExecuting();
 
                try {
-                       switch ($this->command) {
-                               case 'presence':
-                                       $this->executePresence($discord);
-                                       break;
-                               default:
-                                       throw new Exception('unrecognized command');
-                       }
-                       $this->status = 'done';
-                       $this->save();
+                       BaseCommand::resolve($discord, $this)
+                               ->execute()
+                               ->otherwise(function (\Throwable $e) {
+                                       $this->setException($e);
+                               })
+                               ->done(function($v = null) {
+                                       $this->setDone();
+                               });
                } catch (\Exception $e) {
-                       $this->status = 'exception';
-                       $this->result = [
-                               'type' => get_class($e),
-                               'message' => $e->getMessage(),
-                       ];
-                       $this->save();
+                       $this->setException($e);
                }
        }
 
-       protected function executePresence(Discord $discord) {
-               $activity = null;
-               $idle = false;
-               $status = 'online';
-               $afk = false;
-               if (isset($this->parameters['activity'])) {
-                       $activity = new Activity($discord);
-                       $activity->type = $this->parameters['activity'];
-                       if (isset($this->parameters['name'])) {
-                               $activity->name = $this->parameters['name'];
-                       }
-                       if (isset($this->parameters['url'])) {
-                               $activity->url = $this->parameters['url'];
-                       }
-               }
-               if (isset($this->parameters['idle'])) {
-                       $idle = $this->parameters['idle'];
-               }
-               if (isset($this->parameters['status'])) {
-                       $status = $this->parameters['status'];
-               }
-               if (isset($this->parameters['afk'])) {
-                       $afk = $this->parameters['afk'];
-               }
-               $discord->updatePresence($activity, $idle, $status, $afk);
+
+       private function setDone() {
+               $this->status = 'done';
+               $this->save();
        }
 
+       private function setExecuting() {
+               $this->status = 'executing';
+               $this->executed_at = now();
+               $this->save();
+       }
+
+       private function setException(\Throwable $e) {
+               $this->status = 'exception';
+               $this->result = [
+                       'type' => get_class($e),
+                       'file' => $e->getFile(),
+                       'line' => $e->getLine(),
+                       'message' => $e->getMessage(),
+               ];
+               $this->save();
+       }
+
+
        protected $casts = [
                'parameters' => 'array',
                'result' => 'array',
index 308b9e9fcfd2e8935b25a46df87a39e4d991f8b5..99f3791eacfc951acabb8d69d22053f592adbc80 100644 (file)
@@ -11,6 +11,13 @@ class Result extends Model
        use HasFactory;
 
 
+       public function formatTime() {
+               $hours = floor($this->time / 60 / 60);
+               $minutes = floor(($this->time / 60) % 60);
+               $seconds = floor($this->time % 60);
+               return sprintf('%d:%02d:%02d', $hours, $minutes, $seconds);
+       }
+
        public function updateResult($time, $forfeit) {
                $this->time = $time;
                $this->forfeit = $forfeit;
index ff45c6177c234acddda70e6b62493863fb48d151..164fb026bfecba420a784daf83b44697f37cd869 100644 (file)
@@ -12,6 +12,23 @@ class User extends Authenticatable
 {
        use HasApiTokens, HasFactory, Notifiable;
 
+       public function findResult(Round $round) {
+               foreach ($round->results as $result) {
+                       if ($this->id == $result->user_id) {
+                               return $result;
+                       }
+               }
+               return null;
+       }
+
+       public function getName() {
+               if (!empty($this->nickname)) {
+                       return $this->nickname;
+               }
+               return $this->username;
+       }
+
+
        public function isAdmin() {
                return $this->role === 'admin';
        }
diff --git a/lang/de/discord_commands.php b/lang/de/discord_commands.php
new file mode 100644 (file)
index 0000000..1c7880b
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+
+return [
+
+       'result' => [
+               'finish' => ':name hat mit einer Zeit von :time abgeschlossen.',
+               'forfeit' => ':name hat aufgegeben.',
+       ],
+
+];
diff --git a/lang/en/discord_commands.php b/lang/en/discord_commands.php
new file mode 100644 (file)
index 0000000..9003899
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+
+return [
+
+       'result' => [
+               'finish' => ':name has finished with a time of :time.',
+               'forfeit' => ':name has forfeited.',
+       ],
+
+];