public function search(Command $command) : \Generator { if (!$command->hasParameters()) { return new Success(); } $uri = "https://www.google.com/search?q=site:xkcd.com+intitle%3a%22xkcd%3a+%22+" . urlencode(implode(' ', $command->getParameters())); /** @var HttpResponse $response */ $response = (yield $this->httpClient->request($uri)); if ($response->getStatus() !== 200) { return $this->chatClient->postMessage($command->getRoom(), "Useless error message here so debugging this is harder than needed."); } $dom = domdocument_load_html($response->getBody()); $nodes = (new \DOMXPath($dom))->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' g ')]/h3/a"); /** @var \DOMElement $node */ foreach ($nodes as $node) { if (preg_match('~^/url\\?q=(https://xkcd\\.com/\\d+/)~', $node->getAttribute('href'), $matches)) { return $this->chatClient->postMessage($command->getRoom(), $matches[1]); } } if (preg_match('/^(\\d+)$/', trim(implode(' ', $command->getParameters())), $matches) !== 1) { return $this->chatClient->postMessage($command->getRoom(), self::NOT_FOUND_COMIC); } /** @var HttpResponse $response */ $response = (yield $this->httpClient->request('https://xkcd.com/' . $matches[1])); if ($response->getStatus() !== 200) { return $this->chatClient->postMessage($command->getRoom(), self::NOT_FOUND_COMIC); } return $this->chatClient->postMessage($command->getRoom(), 'https://xkcd.com/' . $matches[1]); }
public function run(Command $command) : Generator { if (!$command->hasParameters()) { return $this->chatClient->postMessage($command->getRoom(), self::USAGE); } $form = (new FormBody())->addField("exp", implode(" ", $command->getParameters())); $request = (new Request())->setMethod("POST")->setUri("https://tryhaskell.org/eval")->setBody($form); $response = (yield $this->httpClient->request($request)); return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($response)); }
private function getVersion(CommandMessage $command) : \Generator { if (!(yield $command->getRoom()->isApproved())) { return; } $version = (new SebastianVersion(VERSION, APP_BASE))->getVersion(); $messageText = preg_replace_callback('@v([0-9.]+)(?:-\\d+-g([0-9a-f]+))?@', function ($match) { return sprintf("[%s](%s)", $match[0], empty($match[2]) ? "https://github.com/Room-11/Jeeves/tree/v" . $match[1] : "https://github.com/Room-11/Jeeves/commit/" . $match[2]); }, $version); (yield $this->chatClient->postMessage($command->getRoom(), $messageText)); }
protected function getCommitReference(Command $command, string $path) { list($user, $repo) = explode('/', $path, 2); /** @var HttpResponse $response */ $response = (yield $this->httpClient->request(self::BASE_URL . '/repos/' . urlencode($user) . '/' . urlencode($repo) . '/git/refs/heads/master')); if ($response->getStatus() !== 200) { return $this->chatClient->postMessage($command->getRoom(), "Failed to fetch repo for {$path}"); } $json = json_decode($response->getBody()); if (!isset($json->object->sha)) { return $this->chatClient->postMessage($command->getRoom(), "Failed to fetch reference SHA for {$path}"); } return $json->object->sha; }
public function scrabble(Command $command) : Promise { if ($command->hasParameters() === false) { return $this->chatClient->postMessage($command->getRoom(), self::USAGE); } return $this->chatClient->postReply($command, $this->formatScores($this->calculateScores($this->getScorableWords($command->getParameters())))); }
private function execute(CommandMessage $command) : \Generator { if (!(yield $command->getRoom()->isApproved())) { return; } return $this->chatClient->postReply($command, sprintf('I have been running for %s, since %s', dateinterval_to_string((new \DateTime())->diff($this->startTime)), $this->startTime->format('Y-m-d H:i:s'))); }
public function lmgtfy(Command $command) { $text = $command->getText(); if ((bool) preg_match('~^http://chat\\.stackoverflow\\.com/transcript/message/(\\d+)(#\\d+)?$~', $text)) { $text = (yield $this->messageResolver->resolveMessageText($command->getRoom(), $text)); } return $this->chatClient->postReply($command, $this->getResponse($text)); }
public function questionify(CommandMessage $command) { $text = (yield $this->messageResolver->resolveMessageText($command->getRoom(), $command->getText())); if (preg_match('/\\?\\s*$/', $text)) { return $this->chatClient->postReply($command, 'That\'s already a question'); } return $this->chatClient->postMessage($command->getRoom(), rtrim($text) . '?'); }
public function search(Command $command) : \Generator { if (!$command->hasParameters()) { return new Success(); } $response = (yield $this->httpClient->request('http://www.imdb.com/xml/find?xml=1&nr=1&tt=on&q=' . rawurlencode(implode(' ', $command->getParameters())))); return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($response)); }
public function is(Command $command) : Promise { $reply = random_int(0, 1) ? "yes" : "no"; if (!random_int(0, 15)) { $reply = "dunno"; } $reply = $this->getRandomReply($reply); return $this->chatClient->postMessage($command->getRoom(), $reply); }
public function random(Command $command) : \Generator { if (!$command->hasParameters()) { return new Success(); } /** @var HttpResponse $response */ $response = (yield $this->httpClient->request(self::API_BASE_URL . 'v1/gifs/random?' . http_build_query(['api_key' => $this->apiKey, 'rating' => $this->rating, 'tag' => implode(' ', $command->getParameters())]))); $result = json_decode($response->getBody(), true); return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($result)); }
public function search(Command $command) : \Generator { if (!$command->hasParameters()) { return new Success(); } /** @var HttpResponse $response */ $response = (yield $this->httpClient->request('http://api.urbandictionary.com/v0/define?term=' . rawurlencode(implode(' ', $command->getParameters())))); $result = json_decode($response->getBody(), true); return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($result), PostFlags::TRUNCATE); }
public function getRFC(Command $command) { $rfc = $command->getParameter(0); if ($rfc === null) { // e.g.: !!rfc pipe-operator return $this->chatClient->postMessage($command->getRoom(), "RFC id required"); } $uri = self::BASE_URI . '/' . urlencode($rfc); /** @var HttpResponse $response */ $response = (yield $this->httpClient->request($uri)); if ($response->getStatus() !== 200) { return $this->chatClient->postMessage($command->getRoom(), "Nope, we can't have nice things."); } $votes = self::parseVotes($response->getBody()); if (empty($votes)) { return $this->chatClient->postMessage($command->getRoom(), "No votes found"); } $messages = []; foreach ($votes as $id => $vote) { $breakdown = []; $total = array_sum($vote['votes']); if ($total > 0) { foreach ($vote['votes'] as $option => $value) { $breakdown[] = sprintf("%s (%d: %d%%)", $option, $value, 100 * $value / $total); } } $messages[] = ['name' => $vote['name'], 'href' => $uri . '#' . $id, 'breakdown' => implode(', ', $breakdown)]; } if (count($messages) === 1) { return $this->chatClient->postMessage($command->getRoom(), sprintf("[tag:rfc-vote] [%s](%s) %s", $messages[0]['name'], $messages[0]['href'], $messages[0]['breakdown'])); } $message = implode("\n", array_map(function ($message) { return sprintf('%s %s - %s (%s)', self::BULLET, $message['name'], $message['breakdown'], $message['href']); }, $messages)); return $this->chatClient->postMessage($command->getRoom(), $message); }
public function handleCommand(Command $command) : Promise { return resolve(function () use($command) { $commandName = $command->getCommandName(); if (!isset($this->commands[$commandName])) { return; } $eventId = $command->getEvent()->getId(); $userId = $command->getUserId(); try { $userIsBanned = (yield $this->banStorage->isBanned($command->getRoom(), $userId)); if ($userIsBanned) { $this->logger->log(Level::DEBUG, "User #{$userId} is banned, ignoring event #{$eventId} for built in commands"); return; } $this->logger->log(Level::DEBUG, "Passing event #{$eventId} to built in command handler " . get_class($this->commands[$commandName])); (yield $this->commands[$commandName]->handleCommand($command)); } catch (\Throwable $e) { $this->logger->log(Level::ERROR, "Something went wrong while handling #{$eventId} for built-in commands: {$e}"); } }); }
private function execute(CommandMessage $command) { if (!(yield $command->getRoom()->isApproved())) { return; } if (!in_array($command->getParameter(0), self::ACTIONS, true)) { return; } if ($command->getParameter(0) === "list") { return yield from $this->list($command); } if (!(yield $this->storage->isAdmin($command->getRoom(), $command->getUserId()))) { return $this->chatClient->postReply($command, "I'm sorry Dave, I'm afraid I can't do that"); } switch ($command->getParameter(0)) { case 'add': return yield from $this->add($command, (int) $command->getParameter(1)); case 'remove': return yield from $this->remove($command, (int) $command->getParameter(1)); } throw new \LogicException('Operation ' . $command->getParameter(0) . ' was considered valid but not handled??'); }
public function unpin(Command $command) { $owners = (yield $this->chatClient->getRoomOwners($command->getRoom())); if (!isset($owners[$command->getUserId()])) { return $this->chatClient->postReply($command, "I'm sorry Dave, I'm afraid I can't do that"); } if (!$command->hasParameters(1)) { return $this->chatClient->postReply($command, "You must supply a valid message ID to unpin"); } if (!preg_match('#(?:messages?/)?([0-9]+)#', $command->getParameter(0), $match)) { return $this->chatClient->postReply($command, "You must supply a valid message ID to unpin"); } $key = $match[1]; $id = (int) $key; if (!(yield $this->keyValueStore->exists($key, $command->getRoom()))) { return $this->chatClient->postReply($command, "You must supply a valid message ID to unpin"); } (yield $this->keyValueStore->unset($key, $command->getRoom())); if (in_array($id, (yield $this->chatClient->getPinnedMessages($command->getRoom())))) { (yield $this->chatClient->pinOrUnpinMessage($id, $command->getRoom())); } return $this->chatClient->postMessage($command->getRoom(), "I will no longer repin message #{$id}"); }
/** * Example: * !!github Room-11/Jeeves * * [tag:github-repo] [Room-11/Jeeves](https://github.com/Room-11/Jeeves) Chatbot attempt - * - Watchers: 14, Forks: 15, Last Pushed: 2016-05-26T08:57:41Z * * @param Command $command * @param string $path * @return \Generator */ protected function repo(Command $command, string $path) : \Generator { list($user, $repo) = explode('/', $path, 2); /** @var HttpResponse $response */ $response = (yield $this->httpClient->request('https://api.github.com/repos/' . urlencode($user) . '/' . urlencode($repo))); if ($response->getStatus() !== 200) { return $this->chatClient->postMessage($command->getRoom(), "Failed fetching repo for {$path}"); } $json = json_decode($response->getBody()); if (!isset($json->id)) { return $this->chatClient->postMessage($command->getRoom(), "Unknown repo {$path}"); } return $this->chatClient->postMessage($command->getRoom(), sprintf("[tag:github-repo] [%s](%s) %s - Watchers: %d, Forks: %d, Last Push: %s", $json->full_name, $json->html_url, $json->description, $json->watchers, $json->forks, $json->pushed_at)); }
public function fetch(Command $command) : \Generator { $response = (yield $this->httpClient->request(self::API_URL)); return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($response)); }
public function search(Command $command) : \Generator { if (!$command->hasParameters()) { return new Success(); } $text = implode(' ', $command->getParameters()); $searchTerm = (yield $this->messageResolver->resolveMessageText($command->getRoom(), $text)); $uri = $this->getSearchURL($searchTerm); $request = (new HttpRequest())->setMethod('GET')->setUri($uri)->setHeader('User-Agent', self::USER_AGENT); /** @var HttpResponse $response */ $response = (yield $this->httpClient->request($request)); if ($response->getStatus() !== 200) { return $this->chatClient->postMessage($command->getRoom(), "Google responded with {$response->getStatus()}"); } if (preg_match('#charset\\s*=\\s*([^;]+)#i', trim(implode(', ', $response->getHeader('Content-Type'))), $match) && !preg_match('/' . preg_quote(self::ENCODING, '/') . '/i', $match[1])) { $body = iconv($match[1], self::ENCODING, $response->getBody()); } if (empty($body)) { $body = $response->getBody(); } $dom = domdocument_load_html($body); $xpath = new \DOMXPath($dom); $nodes = $this->getResultNodes($xpath); if ($nodes->length === 0) { return $this->postNoResultsMessage($command); } $searchResults = $this->getSearchResults($nodes, $xpath); $postMessage = $this->getPostMessage($searchResults, $uri, $searchTerm); return $this->chatClient->postMessage($command->getRoom(), $postMessage); }
private function postResult(Command $command, \DOMXPath $xpath, string $url) : Promise { return $this->chatClient->postMessage($command->getRoom(), sprintf("[ [`%s`%s](%s) ] `%s`", $this->getSymbolName($xpath), $this->getSymbolDescription($xpath), $url, $this->getSynopsis($xpath))); }
private function execute(CommandMessage $command) { if (!(yield $command->getRoom()->isApproved())) { return null; } switch ($command->getParameter(0)) { case 'list': return $this->list($command); case 'enable': return $this->enable($command); case 'disable': return $this->disable($command); case 'status': return $this->status($command); } return $this->chatClient->postReply($command, "Syntax: plugin [list|disable|enable] [plugin-name]"); }
private function invokeHandlerForCommand(Command $command) : Promise { $roomIdent = $command->getRoom()->getIdentifier()->getIdentString(); $commandName = $command->getCommandName(); if (!isset($this->commandMap[$roomIdent][$commandName])) { return new Success(); } return resolve(function () use($command, $roomIdent, $commandName) { $userId = $command->getUserId(); $userIsBanned = (yield $this->banStorage->isBanned($command->getRoom(), $userId)); if ($userIsBanned) { $this->logger->log(Level::DEBUG, "User #{$userId} is banned, ignoring event #{$command->getEvent()->getId()} for plugin command endpoints" . " (command: {$commandName})"); return; } /** @var Plugin $plugin */ /** @var PluginCommandEndpoint $endpoint */ list($plugin, $endpoint) = $this->commandMap[$roomIdent][$commandName]; // just a sanity check, shouldn't ever be false but in case something goes horribly wrong if (!$this->isPluginEnabledForRoom($plugin, $command->getRoom())) { $this->logger->log(Level::DEBUG, "Command {$commandName} still present for {$roomIdent} but plugin {$plugin->getName()}" . " is disabled! (endpoint: {$endpoint->getName()})"); return; } (yield $this->invokeCallbackAsPromise($endpoint->getCallback(), $command)); }); }
public function tweet(Command $command) { if (!$this->isMessageValid($command->getParameter(0))) { return new Success(); } if (!(yield $this->admin->isAdmin($command->getRoom(), $command->getUserId()))) { return $this->chatClient->postReply($command, "I'm sorry Dave, I'm afraid I can't do that"); } $tweetText = (yield from $this->getMessage($command, $command->getParameters()[0])); if (mb_strlen($tweetText, "UTF-8") > 140) { return $this->chatClient->postReply($command, "Boo! The message exceeds the 140 character limit. :-("); } $keys = ['oauth.consumer_key', 'oauth.access_token', 'oauth.consumer_secret', 'oauth.access_token_secret']; $config = []; foreach ($keys as $key) { if (!(yield $this->storage->exists($key, $command->getRoom()))) { return $this->chatClient->postReply($command, "I'm not currently configured for tweeting :-("); } $config[$key] = (yield $this->storage->get($key, $command->getRoom())); } $oauthParameters = ["oauth_consumer_key" => $config['oauth.consumer_key'], "oauth_token" => $config['oauth.access_token'], "oauth_nonce" => $this->getNonce(), "oauth_timestamp" => (new \DateTimeImmutable())->format("U"), "oauth_signature_method" => "HMAC-SHA1", "oauth_version" => "1.0", "status" => $tweetText]; $oauthParameters = array_map("rawurlencode", $oauthParameters); asort($oauthParameters); ksort($oauthParameters); $queryString = urldecode(http_build_query($oauthParameters, '', '&')); $baseString = "POST&" . rawurlencode(self::BASE_URI . "/statuses/update.json") . "&" . rawurlencode($queryString); $key = $config['oauth.consumer_secret'] . "&" . $config['oauth.access_token_secret']; $signature = rawurlencode(base64_encode(hash_hmac('sha1', $baseString, $key, true))); $oauthParameters["oauth_signature"] = $signature; $oauthParameters = array_map(function ($value) { return '"' . $value . '"'; }, $oauthParameters); unset($oauthParameters["status"]); asort($oauthParameters); ksort($oauthParameters); $authorizationHeader = $auth = "OAuth " . urldecode(http_build_query($oauthParameters, '', ', ')); $request = (new HttpRequest())->setUri(self::BASE_URI . "/statuses/update.json")->setMethod('POST')->setProtocol('1.1')->setBody('status=' . urlencode($tweetText))->setAllHeaders(['Authorization' => $authorizationHeader, 'Content-Type' => 'application/x-www-form-urlencoded']); /** @var HttpResponse $result */ $result = (yield $this->httpClient->request($request)); $tweetInfo = json_decode($result->getBody(), true); $tweetUri = 'https://twitter.com/' . $tweetInfo['user']['screen_name'] . '/status/' . $tweetInfo['id_str']; return $this->chatClient->postMessage($command->getRoom(), $tweetUri); }
public function toLanguage(Command $command, string $toLanguage = null) : \Generator { $params = $command->getParameters(); if ($params[0] === 'list') { return $this->postSupportedLanguagesList($command->getRoom()); } $toLanguage = $toLanguage ?? array_shift($params); if (null === ($toLanguageCode = $this->getLanguageCode($toLanguage ?? array_shift($params)))) { return $this->chatClient->postReply($command, 'Sorry, I don\'t speak ' . $toLanguage); } $fromLanguageCode = null; if (preg_match('#^--from(?:=(.+))?$#', $params[0] ?? '', $match)) { array_shift($params); $fromLanguage = empty($match[1]) ? array_shift($params) : $match[1]; if (null === ($fromLanguageCode = $this->getLanguageCode($fromLanguage))) { return $this->chatClient->postReply($command, 'Sorry, I don\'t speak ' . $fromLanguage); } } if (count($params) < 1) { return $this->chatClient->postReply($command, 'The empty string is the same in every language'); } $text = (yield from $this->getTextFromArguments($command->getRoom(), $params)); $translation = (yield from $this->getTranslation($command->getRoom(), $text, $toLanguageCode, $fromLanguageCode)); return $this->chatClient->postMessage($command->getRoom(), $translation); }
public function eval(Command $command) : Promise { if (!$command->hasParameters()) { return new Success(); } $code = $this->normalizeCode($command->getText()); $body = (new FormBody())->addField("title", "")->addField("code", $code); $request = (new HttpRequest())->setUri("https://3v4l.org/new")->setMethod("POST")->setHeader("Accept", "application/json")->setBody($body); $deferred = new Deferred(); $this->queue->push([$request, $command->getRoom(), $deferred]); if (!$this->haveLoop) { resolve($this->executeActionsFromQueue()); } return $deferred->promise(); }
private function leave(CommandMessage $command) { try { if ($command->getRoom()->isPermanent()) { (yield $this->chatClient->postReply($command, "This room is my home! I don't need your approval to be here!")); return; } $identifier = $command->getRoom()->getIdentifier(); (yield $this->presenceManager->getRequiredLeaveVoteCount($identifier)); list($hasLeft) = (yield $this->presenceManager->addLeaveVote($identifier, $command->getUserId())); if ($hasLeft) { return; } $message = 'Your vote has been recorded. If I get one more vote within an hour I will leave the room.'; (yield $this->chatClient->postReply($command, $message)); } catch (UserNotAcceptableException $e) { (yield $this->chatClient->postReply($command, "Sorry, only room owners can vote")); } catch (UserAlreadyVotedException $e) { (yield $this->chatClient->postReply($command, "Sorry, you've already voted, you can't vote again")); } }
public function trenslete(CommandMessage $command) { $text = (yield $this->messageResolver->resolveMessageText($command->getRoom(), $command->getText())); return $this->chatClient->postReply($command, $this->ruinPrepositions($text)); }
public function search(Command $command) : Promise { if (!$command->getParameters()) { return new Success(); } $pattern = strtolower(implode(' ', $command->getParameters())); foreach ([$pattern, '$' . $pattern, $pattern . 's', $pattern . 'ing'] as $candidate) { if (isset($this->specialCases[$candidate])) { $result = $this->specialCases[$candidate][0] === '@' && isset($this->specialCases[substr($this->specialCases[$candidate], 1)]) ? $this->specialCases[substr($this->specialCases[$candidate], 1)] : $this->specialCases[$candidate]; return $this->chatClient->postMessage($command->getRoom(), $result); } } if (substr($pattern, 0, 6) === "mysql_") { return $this->chatClient->postMessage($command->getRoom(), $this->getMysqlMessage()); } $pattern = str_replace(['::', '->'], '.', $pattern); $url = self::LOOKUP_URL_BASE . rawurlencode($pattern); return resolve(function () use($command, $pattern, $url) { /** @var HttpResponse $response */ $response = (yield $this->httpClient->request($url)); return $this->chatClient->postMessage($command->getRoom(), $response->getPreviousResponse() !== null ? $this->getMessageFromMatch(yield from $this->preProcessMatch($response, $pattern)) : (yield from $this->getMessageFromSearch($response))); }); }
public function fire(Command $command) : Promise { // !!canon fire return resolve(function () use($command) { return $this->chatClient->postMessage($command->getRoom(), "http://i.imgur.com/s7gEZZC.gif"); }); }
public function getExamples(Command $command) : Promise { $examples = "Examples: \n" . Chars::BULLET . " !!reminder foo at 18:00 \n" . Chars::BULLET . " With timezone: (ie. UTC-3) !!reminder foo at 18:00-3:00 \n" . Chars::BULLET . " !!reminder bar in 2 hours \n" . Chars::BULLET . " !!reminder unset 32901146 \n" . Chars::BULLET . " !!reminder list \n" . Chars::BULLET . " !!in 2 days 42 hours 42 minutes 42 seconds 42! \n" . Chars::BULLET . " !!at 22:00 Grab a beer!"; return resolve(function () use($command, $examples) { return $this->chatClient->postMessage($command->getRoom(), $examples); }); }