setName('talk:bot:install') ->setDescription('Install a new bot on the server') ->addArgument( 'name', InputArgument::REQUIRED, 'The name under which the messages will be posted (min. 1 char, max. 64 chars)' ) ->addArgument( 'secret', InputArgument::REQUIRED, 'Secret used to validate API calls (min. 40 chars, max. 128 chars)' ) ->addArgument( 'url', InputArgument::REQUIRED, 'Webhook endpoint to post messages to (max. 4000 chars)' ) ->addArgument( 'description', InputArgument::OPTIONAL, 'Optional description shown in the admin settings (max. 4000 chars)' ) ->addOption( 'no-setup', null, InputOption::VALUE_NONE, 'Prevent moderators from setting up the bot in a conversation' ) ->addOption( 'feature', 'f', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the list of features for the bot' . "\n" . ' - webhook: The bot receives posted chat messages as webhooks' . "\n" . ' - response: The bot can post messages and reactions as a response' . "\n" . ' - event: The bot reads posted messages from local events' . "\n" . ' - reaction: The bot is notified about adding and removing of reactions' . "\n" . ' - none: When all features should be disabled for the bot' ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $name = $input->getArgument('name'); $secret = $input->getArgument('secret'); $url = $input->getArgument('url'); $description = $input->getArgument('description') ?? ''; $noSetup = $input->getOption('no-setup'); if (!empty($input->getOption('feature'))) { $featureFlags = Bot::featureLabelsToFlags($input->getOption('feature')); if (str_starts_with($url, Bot::URL_APP_PREFIX)) { $featureFlags &= ~Bot::FEATURE_WEBHOOK; } } elseif (str_starts_with($url, Bot::URL_APP_PREFIX)) { $featureFlags = Bot::FEATURE_EVENT; } else { $featureFlags = Bot::FEATURE_WEBHOOK + Bot::FEATURE_RESPONSE; } try { $this->botService->validateBotParameters($name, $secret, $url, $description); } catch (\InvalidArgumentException $e) { $output->writeln('' . $e->getMessage() . ''); return 1; } try { $this->botServerMapper->findByUrl($url); $output->writeln('Bot with the same URL is already registered'); return 2; } catch (DoesNotExistException) { } $bot = new BotServer(); $bot->setName($name); $bot->setSecret($secret); $bot->setUrl($url); $bot->setUrlHash(sha1($url)); $bot->setDescription($description); $bot->setState($noSetup ? Bot::STATE_NO_SETUP : Bot::STATE_ENABLED); $bot->setFeatures($featureFlags); try { $botEntity = $this->botServerMapper->insert($bot); } catch (\Exception $e) { if ($e instanceof Exception && $e->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { $output->writeln('Bot with the same secret is already registered'); return 3; } else { $output->writeln('' . get_class($e) . ': ' . $e->getMessage() . ''); return 1; } } $output->writeln('Bot installed'); $output->writeln('ID: ' . $botEntity->getId()); return 0; } }