🎉 Hello world
commit
eedfbcc2ab
@ -0,0 +1,3 @@
|
||||
/vendor
|
||||
/.idea
|
||||
config.php
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace Shikiryu\Bot;
|
||||
|
||||
class Bot
|
||||
{
|
||||
/**
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
protected $events = [];
|
||||
protected $config = [];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected static $masters = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getMaster()
|
||||
{
|
||||
$masters = array_merge(self::$masters, $this->getConfig()['masters']);
|
||||
return $masters[array_rand($masters, 1)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Bot constructor.
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this->config['token'] === $request->getToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pattern the pattern to listen for
|
||||
* @param \Closure|string $callback the callback to execute. Either a closure or a Class@method notation
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function hears($pattern, $callback)
|
||||
{
|
||||
if (!array_key_exists($pattern, $this->events)) {
|
||||
$this->events[$pattern] = $callback;
|
||||
} else {
|
||||
error_log(sprintf('Event %s déjà en place', $pattern));
|
||||
}
|
||||
|
||||
// $this->events[$pattern][] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to match messages with the ones we should
|
||||
* listen to.
|
||||
*/
|
||||
public function listen($sentence)
|
||||
{
|
||||
foreach ($this->events as $pattern => $command) {
|
||||
$preg_pattern = sprintf('#%s#i', $pattern);
|
||||
if (preg_match($preg_pattern, $sentence, $matches)) {
|
||||
if (is_callable($command)) {
|
||||
call_user_func($command, $this);
|
||||
} else {
|
||||
call_user_func([$command, 'getMessage'], $this, $matches);
|
||||
}
|
||||
} else {
|
||||
error_log(sprintf('%s ne match pas %s', $preg_pattern, $sentence));
|
||||
}
|
||||
}
|
||||
$this->replyPolitely('Je n\'ai pas compris');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
public function replyPolitely($message)
|
||||
{
|
||||
$message .= ', '.$this->getMaster().'.';
|
||||
$this->reply($message);
|
||||
}
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
public function reply($message)
|
||||
{
|
||||
header('Content-type: application/json');
|
||||
die('{"text": "'.$message.'"}');
|
||||
}
|
||||
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Shikiryu\Bot\Commands\Helpers;
|
||||
|
||||
/**
|
||||
* Creates a markdown document based on the parsed documentation
|
||||
*
|
||||
* @author Peter-Christoph Haider <peter.haider@zeyon.net>
|
||||
* @package Apidoc
|
||||
* @version 1.00 (2014-04-04)
|
||||
* @license GNU Lesser Public License
|
||||
*/
|
||||
class TableHelper {
|
||||
|
||||
/** @var int The source path */
|
||||
public $maxlen = 50;
|
||||
/** @var array The source path */
|
||||
private $data = [];
|
||||
/** @var array The source path */
|
||||
private $header = [];
|
||||
/** @var array The source path */
|
||||
private $len = [];
|
||||
/** @var array The source path */
|
||||
private $align = [
|
||||
'name' => 'L',
|
||||
'type' => 'C'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array $header The header array [key => label, ...]
|
||||
* @param array $content Content
|
||||
* @param array|bool $align Alignment options [key => L|R|C, ...]
|
||||
*/
|
||||
public function __construct($header = null, $content = [], $align=false)
|
||||
{
|
||||
if ($header) {
|
||||
$this->header = $header;
|
||||
} elseif ($content) {
|
||||
foreach ($content[0] as $key => $value) {
|
||||
$this->header[$key] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->header as $key => $label) {
|
||||
$this->len[$key] = strlen($label);
|
||||
}
|
||||
|
||||
if (is_array($align)) {
|
||||
$this->setAlign($align);
|
||||
}
|
||||
|
||||
$this->addData($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the alignment array
|
||||
*
|
||||
* @param array $align Alignment options [key => L|R|C, ...]
|
||||
*/
|
||||
public function setAlign($align) {
|
||||
$this->align = $align;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data to the table
|
||||
*
|
||||
* @param array $content Content
|
||||
* @return TableHelper
|
||||
*/
|
||||
public function addData($content) {
|
||||
foreach ($content as &$row) {
|
||||
foreach ($this->header as $key => $value) {
|
||||
if (!isset($row[$key])) {
|
||||
$row[$key] = '-';
|
||||
} elseif (strlen($row[$key]) > $this->maxlen) {
|
||||
$this->len[$key] = $this->maxlen;
|
||||
$row[$key] = substr($row[$key], 0, $this->maxlen-3).'...';
|
||||
} elseif (strlen($row[$key]) > $this->len[$key]) {
|
||||
$this->len[$key] = strlen($row[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($row);
|
||||
$this->data += $content;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a delimiter
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function renderDelimiter() {
|
||||
$res = '|';
|
||||
foreach ($this->len as $key => $l) {
|
||||
$res .= (isset($this->align[$key]) && ($this->align[$key] === 'C' || $this->align[$key] === 'L') ? ':' : ' ')
|
||||
. str_repeat('-', $l)
|
||||
. (isset($this->align[$key]) && ($this->align[$key] === 'C' || $this->align[$key] === 'R') ? ':' : ' ')
|
||||
. '|';
|
||||
}
|
||||
return $res."\r\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single row
|
||||
*
|
||||
* @param array $row
|
||||
* @return string
|
||||
*/
|
||||
private function renderRow($row) {
|
||||
$res = '|';
|
||||
foreach ($this->len as $key => $l) {
|
||||
$res .= ' '.$row[$key].($l > strlen($row[$key]) ? str_repeat(' ', $l - strlen($row[$key])) : '').' |';
|
||||
}
|
||||
|
||||
return $res."\r\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the table
|
||||
*
|
||||
* @param array $content Additional table content
|
||||
* @return string
|
||||
*/
|
||||
public function render($content=array()) {
|
||||
$this->addData($content);
|
||||
|
||||
$res = $this->renderRow($this->header) . $this->renderDelimiter();
|
||||
foreach ($this->data as $row) {
|
||||
$res .= $this->renderRow($row);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Shikiryu\Bot\Commands;
|
||||
|
||||
use Shikiryu\Bot\Bot;
|
||||
|
||||
interface Icommands
|
||||
{
|
||||
public static function getMessage(Bot $bot, array $data);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getDescription();
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Shikiryu\Bot\Commands;
|
||||
|
||||
use JsonRPC\Client;
|
||||
use Shikiryu\Bot\Bot;
|
||||
|
||||
class Tasks implements Icommands
|
||||
{
|
||||
public static function getMessage(Bot $bot, array $data)
|
||||
{
|
||||
$config = $bot->getConfig();
|
||||
if (!array_key_exists('kanboard', $config)) {
|
||||
$bot->replyPolitely('Je n\'ai pas la configuration nécessaire');
|
||||
}
|
||||
$config = $config['kanboard'];
|
||||
$client = new Client($config['url']);
|
||||
$client->authentication('jsonrpc', $config['token']);
|
||||
|
||||
$task = $data[1];
|
||||
$project = $data[2];
|
||||
|
||||
if (!is_numeric($project)) {
|
||||
$asked_project = strtolower($project);
|
||||
$projects = $client->getAllProjects();
|
||||
foreach ($projects as $project) {
|
||||
if (strtolower($project['name']) === $asked_project) {
|
||||
$project = (int) $project['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$new_task = $client->createTask([
|
||||
'title' => $task,
|
||||
'project_id' => $project,
|
||||
]);
|
||||
|
||||
if ($new_task === false) {
|
||||
$bot->replyPolitely('La tâche n\'a pas pu être ajoutée.');
|
||||
} else {
|
||||
$bot->replyPolitely(sprintf('Tâche ajoutée. Elle porte le n°%u', $new_task));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getDescription()
|
||||
{
|
||||
return 'Ajoute une tâche dans Kanboard';
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Shikiryu\Bot\Commands;
|
||||
|
||||
use JsonRPC\Client;
|
||||
use Shikiryu\Bot\Bot;
|
||||
|
||||
class TasksList implements Icommands
|
||||
{
|
||||
public static function getMessage(Bot $bot, array $data)
|
||||
{
|
||||
$config = $bot->getConfig();
|
||||
if (!array_key_exists('kanboard', $config)) {
|
||||
$bot->replyPolitely('Je n\'ai pas la configuration nécessaire');
|
||||
}
|
||||
$config = $config['kanboard'];
|
||||
$client = new Client($config['url']);
|
||||
$client->authentication('jsonrpc', $config['token']);
|
||||
|
||||
$project = $data[1];
|
||||
|
||||
if (!is_numeric($project)) {
|
||||
$asked_project = strtolower($project);
|
||||
$projects = $client->getAllProjects();
|
||||
foreach ($projects as $project) {
|
||||
if (strtolower($project['name']) === $asked_project) {
|
||||
$project = (int) $project['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$task_list = $client->getAllTasks([
|
||||
'project_id' => $project,
|
||||
]);
|
||||
|
||||
if ($task_list === false) {
|
||||
$bot->replyPolitely('Je n\'ai pas réussi à récupérer la liste');
|
||||
} else {
|
||||
if (empty($task_list)) {
|
||||
$bot->replyPolitely('Il n\'y a pas de tâches dans ce projet');
|
||||
}
|
||||
$task_list = array_map(function($task) { return sprintf('%u: %s', $task['id'], $task['title']); }, $task_list);
|
||||
$bot->replyPolitely(sprintf('Voici la liste des tâches du projet %u : %s', $project, implode('\n', $task_list)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getDescription()
|
||||
{
|
||||
return 'Liste les tâches d\'un projet Kanboard';
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Shikiryu\Bot\Commands;
|
||||
|
||||
use JsonRPC\Client;
|
||||
use Shikiryu\Bot\Bot;
|
||||
|
||||
class TasksProjects implements Icommands
|
||||
{
|
||||
public static function getMessage(Bot $bot, array $data)
|
||||
{
|
||||
$config = $bot->getConfig();
|
||||
if (!array_key_exists('kanboard', $config)) {
|
||||
$bot->replyPolitely('Je n\'ai pas la configuration nécessaire');
|
||||
}
|
||||
$config = $config['kanboard'];
|
||||
$client = new Client($config['url']);
|
||||
$client->authentication('jsonrpc', $config['token']);
|
||||
|
||||
$projects = $client->getAllProjects();
|
||||
|
||||
$projects = array_filter($projects, function($project) { return $project['is_active']; });
|
||||
$projects = array_map(function($project) { return sprintf('%u: %s', $project['id'], $project['name']); }, $projects);
|
||||
|
||||
$bot->replyPolitely(sprintf('Voici vos différents projets : %s', implode(', ', $projects)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getDescription()
|
||||
{
|
||||
return 'Liste les projets de Kanboard';
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Shikiryu\Bot\Commands;
|
||||
|
||||
use Shikiryu\Bot\Bot;
|
||||
|
||||
class Youtubedl implements Icommands
|
||||
{
|
||||
|
||||
public static function getMessage(Bot $bot, array $data)
|
||||
{
|
||||
$action = strtolower($data[1]); // ex: télécharge
|
||||
$url = filter_var($data[2], FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED); // ex: https://www.youtube.com/watch?v=3BXDsVD6O10
|
||||
$type = $data[3]; // ex: audio
|
||||
|
||||
if (empty($url)) {
|
||||
$bot->replyPolitely('L\'url n\'est pas conforme');
|
||||
}
|
||||
|
||||
if (!in_array($type, ['', 'audio', 'video'], true)) {
|
||||
$bot->replyPolitely('Je n\'ai pas compris ce que je devais faire');
|
||||
}
|
||||
|
||||
if (in_array($type, ['', 'audio'], true)) {
|
||||
$type = 'l\'audio';
|
||||
exec("youtube-dl --extract-audio --audio-format mp3 -o '/volume1/music/Podcast/Youtube/%(upload_date)s-%(uploader)s-%(title)s.%(ext)s' $url &> /dev/null &");
|
||||
} else {
|
||||
$type = 'la vidéo';
|
||||
exec("youtube-dl -f bestvideo+bestaudio/best -o '/volume1/music/Podcast/Youtube/%(upload_date)s-%(uploader)s-%(title)s.%(ext)s' $url &> /dev/null &");
|
||||
}
|
||||
$bot->replyPolitely(sprintf('Je %s %s', $action, $type));
|
||||
}
|
||||
|
||||
public static function getDescription()
|
||||
{
|
||||
return 'Youtubedl wrapper';
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Shikiryu\Bot;
|
||||
|
||||
class Request
|
||||
{
|
||||
protected $token;
|
||||
protected $user_id;
|
||||
protected $username;
|
||||
protected $post_id;
|
||||
protected $timestamp;
|
||||
protected $text;
|
||||
|
||||
/**
|
||||
* Request constructor.
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(array $data)
|
||||
{
|
||||
if (isset($data['token'])) {
|
||||
$this->token = $data['token'];
|
||||
}
|
||||
|
||||
if (isset($data['user_id'])) {
|
||||
$this->user_id = $data['user_id'];
|
||||
}
|
||||
|
||||
if (isset($data['username'])) {
|
||||
$this->username = $data['username'];
|
||||
}
|
||||
|
||||
if (isset($data['post_id'])) {
|
||||
$this->post_id = $data['post_id'];
|
||||
}
|
||||
|
||||
if (isset($data['timestamp'])) {
|
||||
$this->timestamp = $data['timestamp'];
|
||||
}
|
||||
|
||||
if (isset($data['text'])) {
|
||||
$this->text = $data['text'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUserId()
|
||||
{
|
||||
return $this->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPostId()
|
||||
{
|
||||
return $this->post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTimestamp()
|
||||
{
|
||||
return $this->timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getText()
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"require": {
|
||||
"fguillot/json-rpc": "@stable",
|
||||
"ext-soap": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Shikiryu\\Bot\\": "bot/"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "5ba319f496d82db0def48509079b247a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "fguillot/json-rpc",
|
||||
"version": "v1.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fguillot/JsonRPC.git",
|
||||
"reference": "ea2720b13e986bbf23e832b135c84c91ead7259f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/ea2720b13e986bbf23e832b135c84c91ead7259f",
|
||||
"reference": "ea2720b13e986bbf23e832b135c84c91ead7259f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.8.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"JsonRPC": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frédéric Guillot"
|
||||
}
|
||||
],
|
||||
"description": "Simple Json-RPC client/server library that just works",
|
||||
"homepage": "https://github.com/fguillot/JsonRPC",
|
||||
"time": "2017-01-12T21:31:30+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"fguillot/json-rpc": 0
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'url' => '',
|
||||
'token' => '',
|
||||
'kanboard' => [
|
||||
'url' => '',
|
||||
'token'=> '',
|
||||
],
|
||||
'masters' => [
|
||||
'Maître',
|
||||
'Monsieur',
|
||||
'Seigneur',
|
||||
'Doyen',
|
||||
'Monseigneur',
|
||||
],
|
||||
];
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Shikiryu\Bot\Bot;
|
||||
use Shikiryu\Bot\Commands\Lorem;
|
||||
use Shikiryu\Bot\Commands\Tasks;
|
||||
use Shikiryu\Bot\Commands\TasksList;
|
||||
use Shikiryu\Bot\Commands\TasksProjects;
|
||||
use Shikiryu\Bot\Commands\Youtubedl;
|
||||
use Shikiryu\Bot\Request;
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('log_errors', 1);
|
||||
|
||||
$config = include 'config.php';
|
||||
|
||||
$bot = new Bot($config);
|
||||
|
||||
$request = new Request($_POST);
|
||||
|
||||
if (!$bot->isValid($request)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Give the bot something to listen for.
|
||||
$bot->hears('(convertis|télécharges?) (https?:\/\/[^\s]+) en (audio|video|vidéo)', Youtubedl::class);
|
||||
|
||||
$bot->hears('lorem( ipsum)?', Lorem::class);
|
||||
|
||||
$bot->hears('liste.*projets?', TasksProjects::class);
|
||||
|
||||
$bot->hears('ajoute.*t(a|â)che (.*) dans "(.*)"', Tasks::class);
|
||||
|
||||
$bot->hears('(?:donne|liste).*t(?:a|â)ches? de "(.*)"', TasksList::class);
|
||||
|
||||
$bot->hears('(hello|hi|bonjour|salut)', function (Bot $bot) {
|
||||
$bot->replyPolitely('Bonjour');
|
||||
});
|
||||
|
||||
// Start listening
|
||||
$bot->listen($_POST['text']);
|
||||
|
Loading…
Reference in New Issue