Merged in feature_telegram_bot (pull request #12)

Telegram bot
This commit is contained in:
Alexey Eschenko 2017-01-05 01:43:00 +03:00
commit fd2e1d81f8
20 changed files with 902 additions and 63 deletions

View file

@ -59,6 +59,18 @@ You can use following jobs as an example:
0 0 * * * /usr/bin/php /path/to/point-tools/app/console point:update:subscriptions --all-users --env=prod 0 0 * * * /usr/bin/php /path/to/point-tools/app/console point:update:subscriptions --all-users --env=prod
``` ```
## Setting Telegram webhook (to enable bot)
```shell
php app/console telegram:webhook set your-domain.tld
```
## Removing Telegram webhook
```shell
php app/console telegram:webhook delete
```
# Running tests # Running tests
## Configure environment variables ## Configure environment variables

View file

@ -19,6 +19,7 @@ class AppKernel extends Kernel
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new JMS\SerializerBundle\JMSSerializerBundle(), new JMS\SerializerBundle\JMSSerializerBundle(),
new Misd\GuzzleBundle\MisdGuzzleBundle(), new Misd\GuzzleBundle\MisdGuzzleBundle(),
new Csa\Bundle\GuzzleBundle\CsaGuzzleBundle(),
new Ob\HighchartsBundle\ObHighchartsBundle(), new Ob\HighchartsBundle\ObHighchartsBundle(),
new Knp\Bundle\MarkdownBundle\KnpMarkdownBundle(), new Knp\Bundle\MarkdownBundle\KnpMarkdownBundle(),
new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(), new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(),

View file

@ -90,3 +90,6 @@ knp_markdown:
knp_paginator: knp_paginator:
template: template:
pagination: KnpPaginatorBundle:Pagination:twitter_bootstrap_v3_pagination.html.twig pagination: KnpPaginatorBundle:Pagination:twitter_bootstrap_v3_pagination.html.twig
csa_guzzle:
profiler: '%kernel.debug%'

View file

@ -24,3 +24,7 @@ parameters:
# Token for Go crawler https://bitbucket.org/skobkin/point-tools-crawler # Token for Go crawler https://bitbucket.org/skobkin/point-tools-crawler
crawler_token: test_token crawler_token: test_token
# Telegram bot
telegram_token: "123456:some-token"
telegram_max_connections: 2

View file

@ -24,7 +24,9 @@
"doctrine/doctrine-migrations-bundle": "^1.0", "doctrine/doctrine-migrations-bundle": "^1.0",
"jms/serializer-bundle": "^1.1", "jms/serializer-bundle": "^1.1",
"knplabs/knp-markdown-bundle": "^1.4", "knplabs/knp-markdown-bundle": "^1.4",
"knplabs/knp-paginator-bundle": "^2.5" "knplabs/knp-paginator-bundle": "^2.5",
"unreal4u/telegram-api": "^2.2",
"csa/guzzle-bundle": "^2.1"
}, },
"require-dev": { "require-dev": {
"sensio/generator-bundle": "~2.3", "sensio/generator-bundle": "~2.3",

384
composer.lock generated
View file

@ -4,8 +4,69 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "2afa2daba03d5922ce606ef250dae660", "content-hash": "f890dca974c5dbd0ada78afc457f249b",
"packages": [ "packages": [
{
"name": "csa/guzzle-bundle",
"version": "v2.1.2",
"source": {
"type": "git",
"url": "https://github.com/csarrazi/CsaGuzzleBundle.git",
"reference": "9796e5c28e02d5c2f0aa1376e8390b1d29159d28"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/csarrazi/CsaGuzzleBundle/zipball/9796e5c28e02d5c2f0aa1376e8390b1d29159d28",
"reference": "9796e5c28e02d5c2f0aa1376e8390b1d29159d28",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6.1",
"namshi/cuzzle": "^2.0",
"php": ">=5.5.0",
"symfony/dependency-injection": "^2.6|^3.0",
"symfony/expression-language": "^2.6|^3.0",
"symfony/filesystem": "^2.3|^3.0",
"symfony/framework-bundle": "^2.6|^3.0",
"twig/twig": "^1.12|^2.0"
},
"conflict": {
"guzzlehttp/command": "*",
"guzzlehttp/guzzle-services": "*"
},
"require-dev": {
"doctrine/cache": "^1.1",
"phpunit/phpunit": "^4.8",
"symfony/phpunit-bridge": "^2.7|^3.0",
"symfony/web-profiler-bundle": "^2.3|^3.0"
},
"suggest": {
"doctrine/cache": "Allows caching of responses"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "2.2.x-dev"
}
},
"autoload": {
"psr-4": {
"Csa\\Bundle\\GuzzleBundle\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Charles Sarrazin",
"email": "charles@sarraz.in"
}
],
"description": "A bundle integrating GuzzleHttp >= 4.0",
"time": "2016-08-25T12:09:22+00:00"
},
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
"version": "v1.3.0", "version": "v1.3.0",
@ -1004,6 +1065,177 @@
"abandoned": "guzzlehttp/guzzle", "abandoned": "guzzlehttp/guzzle",
"time": "2015-03-18T18:23:50+00:00" "time": "2015-03-18T18:23:50+00:00"
}, },
{
"name": "guzzlehttp/guzzle",
"version": "6.2.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ebf29dee597f02f09f4d5bbecc68230ea9b08f60",
"reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.3.1",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.0",
"psr/log": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.2-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2016-10-08T15:01:37+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"time": "2016-12-20T10:07:11+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
"reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "PSR-7 message implementation",
"keywords": [
"http",
"message",
"stream",
"uri"
],
"time": "2016-06-24T23:00:38+00:00"
},
{ {
"name": "incenteev/composer-parameter-handler", "name": "incenteev/composer-parameter-handler",
"version": "v2.1.2", "version": "v2.1.2",
@ -1809,6 +2041,56 @@
], ],
"time": "2016-11-26T00:15:39+00:00" "time": "2016-11-26T00:15:39+00:00"
}, },
{
"name": "namshi/cuzzle",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/namshi/cuzzle.git",
"reference": "89849bb9c729a3d8aabf94c0b66e77c7df38abda"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/namshi/cuzzle/zipball/89849bb9c729a3d8aabf94c0b66e77c7df38abda",
"reference": "89849bb9c729a3d8aabf94c0b66e77c7df38abda",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6.0",
"php": ">=5.5.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.2.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Namshi\\Cuzzle\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nikita Nefedov",
"email": "inefedor@gmail.com"
},
{
"name": "cirpo",
"email": "alessandro.cinelli@gmail.com"
}
],
"description": "Get the cURL shell command from a Guzzle request",
"time": "2016-11-23T08:01:36+00:00"
},
{ {
"name": "ob/highcharts-bundle", "name": "ob/highcharts-bundle",
"version": "1.5", "version": "1.5",
@ -2072,6 +2354,56 @@
], ],
"time": "2015-07-25T16:39:46+00:00" "time": "2015-07-25T16:39:46+00:00"
}, },
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2016-08-06T14:39:51+00:00"
},
{ {
"name": "psr/log", "name": "psr/log",
"version": "1.0.2", "version": "1.0.2",
@ -2880,6 +3212,56 @@
], ],
"time": "2016-11-23T18:41:40+00:00" "time": "2016-11-23T18:41:40+00:00"
}, },
{
"name": "unreal4u/telegram-api",
"version": "v2.2.0",
"source": {
"type": "git",
"url": "https://github.com/unreal4u/telegram-api.git",
"reference": "dd6f58387569d045bf2581dff909f7874bf7d27a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/unreal4u/telegram-api/zipball/dd6f58387569d045bf2581dff909f7874bf7d27a",
"reference": "dd6f58387569d045bf2581dff909f7874bf7d27a",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "~6.0",
"php": ">=7.0.0",
"psr/log": "~1.0"
},
"require-dev": {
"monolog/monolog": "~1.17",
"phpunit/php-code-coverage": "~3.3",
"phpunit/phpunit": ">=5.2",
"squizlabs/php_codesniffer": "~2.3"
},
"type": "library",
"autoload": {
"psr-4": {
"unreal4u\\TelegramAPI\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Camilo Sperberg",
"email": "me@unreal4u.com",
"homepage": "https://github.com/unreal4u/telegram-api/graphs/contributors"
}
],
"description": "A complete Telegram bot API implementation written in PHP, with support for inline bots!",
"keywords": [
"api",
"telegram",
"telegram bot"
],
"time": "2016-12-04T10:20:14+00:00"
},
{ {
"name": "zendframework/zend-code", "name": "zendframework/zend-code",
"version": "2.6.3", "version": "2.6.3",

View file

@ -0,0 +1,79 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use unreal4u\TelegramAPI\Telegram\Methods\DeleteWebhook;
use unreal4u\TelegramAPI\Telegram\Methods\SetWebhook;
/**
* Sets or deletes Telegram bot Web-Hook
* @see https://core.telegram.org/bots/api#setwebhook
*/
class TelegramSetWebHookCommand extends ContainerAwareCommand
{
const MODE_SET = 'set';
const MODE_DELETE = 'delete';
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('telegram:webhook')
->setDescription('Set webhook')
->addArgument('mode', InputArgument::REQUIRED, 'Command mode (set or delete)')
->addArgument('host', InputArgument::OPTIONAL, 'Host of telegram hook')
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$container = $this->getContainer();
$telegramClient = $container->get('point_tools.telegram.api_client');
if (self::MODE_SET === strtolower($input->getArgument('mode'))) {
if (!$input->hasArgument('host')) {
throw new \InvalidArgumentException('Host must be specified when using --set flag');
}
$router = $container->get('router');
$token = $container->getParameter('telegram_token');
$url = sprintf(
'https://%s%s',
$input->getArgument('host'),
$router->generate('telegram_webhook', ['token' => $token])
);
$output->writeln('Setting webhook: '.$url);
$setWebHook = new SetWebhook();
$setWebHook->url = $url;
$setWebHook->max_connections = (int) $container->getParameter('telegram_max_connections');
$telegramClient->performApiRequest($setWebHook);
$output->writeln('Done');
} elseif (self::MODE_DELETE === strtolower($input->getArgument('mode'))) {
$output->writeln('Deleting webhook');
$deleteWebHook = new DeleteWebhook();
$telegramClient->performApiRequest($deleteWebHook);
$output->writeln('Done');
} else {
throw new \InvalidArgumentException(sprintf('Mode must be exaclty one of: %s', implode(', ', [self::MODE_SET, self::MODE_DELETE])));
}
return 0;
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Controller\Telegram;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use unreal4u\TelegramAPI\Telegram\Types\Update;
/**
* {@inheritdoc}
*/
class WebHookController extends Controller
{
public function receiveUpdateAction(Request $request, $token)
{
if ($token !== $savedToken = $this->getParameter('telegram_token')) {
throw $this->createNotFoundException();
}
$content = json_decode($request->getContent(), true);
$update = new Update(
$content,
$this->get('logger')
);
$this->get('point_tools.telegram.update_processor')->process($update);
return new JsonResponse('received');
}
}

View file

@ -53,14 +53,14 @@ class User
/** /**
* @var ArrayCollection * @var ArrayCollection
* *
* @ORM\OneToMany(targetEntity="Subscription", mappedBy="author") * @ORM\OneToMany(targetEntity="Subscription", mappedBy="author", fetch="EXTRA_LAZY")
*/ */
private $subscribers; private $subscribers;
/** /**
* @var ArrayCollection * @var ArrayCollection
* *
* @ORM\OneToMany(targetEntity="Subscription", mappedBy="subscriber") * @ORM\OneToMany(targetEntity="Subscription", mappedBy="subscriber", fetch="EXTRA_LAZY")
*/ */
private $subscriptions; private $subscriptions;

View file

@ -48,7 +48,7 @@ class SubscriptionEventRepository extends EntityRepository
} }
/** /**
* Get last subscriptions QueryBuilder for pagination * Get last global subscriptions QueryBuilder for pagination
* *
* @return QueryBuilder * @return QueryBuilder
*/ */
@ -63,4 +63,19 @@ class SubscriptionEventRepository extends EntityRepository
->orderBy('se.date', 'desc') ->orderBy('se.date', 'desc')
; ;
} }
/**
* Get last global subscription events
*
* @param int $limit
*
* @return SubscriptionEvent[]
*/
public function getLastSubscriptionEvents($limit = 20)
{
$qb = $this->createLastSubscriptionEventsQuery();
$qb->setMaxResults($limit);
return $qb->getQuery()->getResult();
}
} }

View file

@ -2,6 +2,14 @@ index:
path: / path: /
defaults: { _controller: SkobkinPointToolsBundle:Main:index } defaults: { _controller: SkobkinPointToolsBundle:Main:index }
telegram_webhook:
path: /telegram/webhook/{token}
defaults: { _controller: SkobkinPointToolsBundle:Telegram/WebHook:receiveUpdate, _format: json }
methods: [POST]
requirements:
token: "\d+\:[\w-]+"
_format: json
user_search_ajax: user_search_ajax:
path: /ajax/users/search/{login} path: /ajax/users/search/{login}
defaults: { _controller: SkobkinPointToolsBundle:Main:searchUserAjax, _format: json } defaults: { _controller: SkobkinPointToolsBundle:Main:searchUserAjax, _format: json }

View file

@ -1,4 +1,13 @@
services: services:
# Guzzle 6 client for Telegram
point_tools.http.telegram_client:
class: GuzzleHttp\Client
arguments: [{ timeout: 3.0 }]
tags:
- { name: csa_guzzle.client }
# Guzzle 5 client for Point API
# TODO upgrade and remove misd bundle
skobkin_point_tools.http_client: skobkin_point_tools.http_client:
class: %guzzle.client.class% class: %guzzle.client.class%
arguments: [ "%point_base_url%" ] arguments: [ "%point_base_url%" ]
@ -68,8 +77,23 @@ services:
# Twig extensions # Twig extensions
point_tools.twig.point_avatar_extension: point_tools.twig.point_avatar_extension:
class: Skobkin\Bundle\PointToolsBundle\Twig\PointAvatarExtension class: Skobkin\Bundle\PointToolsBundle\Twig\PointUserExtension
public: false public: false
arguments: ['@skobkin_point_tools.api_user'] arguments: ['@skobkin_point_tools.api_user']
tags: tags:
- { name: twig.extension } - { name: twig.extension }
# Telegram API client
point_tools.telegram.api_client:
class: unreal4u\TelegramAPI\TgLog
arguments: [%telegram_token%, @logger, @point_tools.http.telegram_client]
# Telegram simple message sender
point_tools.telegram.simple_sender:
class: Skobkin\Bundle\PointToolsBundle\Service\Telegram\SimpleSender
arguments: [@point_tools.telegram.api_client]
# Telegram command processor
point_tools.telegram.update_processor:
class: Skobkin\Bundle\PointToolsBundle\Service\Telegram\IncomingUpdateProcessor
arguments: [%point_id%, @point_tools.telegram.api_client, @doctrine.orm.entity_manager, @twig]

View file

@ -0,0 +1,7 @@
*Help*:
/last - shows last global subscription events
/last %user% - shows last user subscribers events
/help shows this message
Visit [Point Tools](https://point.skobk.in/) for more info.

View file

@ -0,0 +1,11 @@
Last global subscription events:
{% set subscription = constant('\\Skobkin\\Bundle\\PointToolsBundle\\Entity\\SubscriptionEvent::ACTION_SUBSCRIBE') %}
{# @var event \Skobkin\Bundle\PointToolsBundle\Entity\SubscriptionEvent #}
{% for event in events %}
{% set sub_login = event.subscriber.login %}
{% set author_login = event.author.login %}
{{ event.date|date('d M H:i') }} [@{{ sub_login }}]({{ sub_login|point_user_url(true) }}){% if subscription == event.action %} -> {% else %} X {% endif %}[@{{ author_login }}]({{ author_login|point_user_url(true) }})
{% endfor %}
See more events on [Point Tools](https://point.skobk.in/) site.

View file

@ -0,0 +1,7 @@
*Point Tools statistics:*
Total users: {{ total_users }}
Active users: {{ active_users }}
24 hours events: {{ today_events }}
Visit [Point Tools](https://point.skobk.in/) for more info.

View file

@ -5,7 +5,7 @@
{% block content %} {% block content %}
<h1 class="user-login"> <h1 class="user-login">
<img src="{{ avatar_url }}"> <img src="{{ avatar_url }}">
<a href="//{{ user.login }}.point.im/blog/" target="_blank">{{ user.login }}</a> <a href="{{ user.login|point_user_blog_url }}" target="_blank">{{ user.login }}</a>
</h1> </h1>
<div class="user-subscribers"> <div class="user-subscribers">

View file

@ -0,0 +1,170 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Service\Telegram;
use Doctrine\ORM\EntityManagerInterface;
use unreal4u\TelegramAPI\Telegram\Methods\AnswerInlineQuery;
use unreal4u\TelegramAPI\Telegram\Methods\SendMessage;
use unreal4u\TelegramAPI\Telegram\Types\Inline\Query;
use unreal4u\TelegramAPI\Telegram\Types\InputMessageContent\Text;
use unreal4u\TelegramAPI\Telegram\Types\Message;
use unreal4u\TelegramAPI\Telegram\Types\Update;
use unreal4u\TelegramAPI\TgLog;
/**
* @todo refactor
*/
class IncomingUpdateProcessor
{
const CHAT_TYPE_PRIVATE = 'private';
const CHAT_TYPE_GROUP = 'group';
const PARSE_MODE_MARKDOWN = 'Markdown';
const PARSE_MODE_HTML5 = 'HTML';
/**
* @var TgLog
*/
private $client;
/**
* @var EntityManagerInterface
*/
private $em;
/**
* @var \Twig_Environment
*/
private $twig;
/**
* @var int
*/
private $pointUserId;
/**
* @param TgLog $client
*/
public function __construct(int $pointUserId, TgLog $client, EntityManagerInterface $em, \Twig_Environment $twig)
{
$this->client = $client;
$this->em = $em;
$this->twig = $twig;
$this->pointUserId = $pointUserId;
}
/**
* Processes update and delegates it to corresponding service
*
* @param Update $update
*/
public function process(Update $update)
{
if ($update->message && $update->message instanceof Message) {
$chatType = $update->message->chat->type;
if (self::CHAT_TYPE_PRIVATE === $chatType) {
$this->processPrivateMessage($update);
} elseif (self::CHAT_TYPE_GROUP === $chatType) {
}
} elseif ($update->inline_query && $update->inline_query instanceof Query) {
$this->processInlineQuery($update);
}
}
/**
* @todo refactor
*
* @param Update $update
*/
private function processPrivateMessage(Update $update)
{
$chatId = $update->message->chat->id;
$text = $update->message->text;
$sendMessage = new SendMessage();
$sendMessage->chat_id = $chatId;
$sendMessage->parse_mode = self::PARSE_MODE_MARKDOWN;
$sendMessage->disable_web_page_preview = true;
$words = explode(' ', $text, 3);
if (0 === count($words)) {
return;
}
switch ($words[0]) {
case 'l':
case '/last':
case 'last':
if (array_key_exists(1, $words)) {
$sendMessage->text = 'Not implemented yet :(';
} else {
$events = $this->em->getRepository('SkobkinPointToolsBundle:SubscriptionEvent')->getLastSubscriptionEvents(10);
$sendMessage->text = $this->twig->render('@SkobkinPointTools/Telegram/last_global_subscriptions.md.twig', ['events' => $events]);
}
break;
case 'sub':
case '/sub':
case 'subscribers':
$sendMessage->text = 'Subscribers list here...';
break;
case 'stats':
case '/stats':
$stats = [
'total_users' => $this->em->getRepository('SkobkinPointToolsBundle:User')->getUsersCount(),
'active_users' => $this->em->getRepository('SkobkinPointToolsBundle:Subscription')->getUserSubscribersCountById($this->pointUserId),
'today_events' => $this->em->getRepository('SkobkinPointToolsBundle:SubscriptionEvent')->getLastDayEventsCount(),
];
$sendMessage->text = $this->twig->render('@SkobkinPointTools/Telegram/stats.md.twig', $stats);
break;
case '/help':
default:
$sendMessage->text = $this->twig->render('@SkobkinPointTools/Telegram/help.md.twig');
break;
}
$this->client->performApiRequest($sendMessage);
}
private function processInlineQuery(Update $update)
{
$queryId = $update->inline_query->id;
$text = $update->inline_query->query;
if (mb_strlen($text) < 2) {
return;
}
$answerInlineQuery = new AnswerInlineQuery();
$answerInlineQuery->inline_query_id = $queryId;
foreach ($this->em->getRepository('SkobkinPointToolsBundle:User')->findUsersLikeLogin($text) as $user) {
$article = new Query\Result\Article();
$article->title = $user->getLogin();
$contentText = new Text();
$contentText->message_text = sprintf(
"@%s:\nName: %s\nSubscribers: %d",
$user->getLogin(),
$user->getName(),
$user->getSubscribers()->count()
);
$article->input_message_content = $contentText;
$article->id = md5($user->getId());
$answerInlineQuery->addResult($article);
}
$this->client->performApiRequest($answerInlineQuery);
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Service\Telegram;
use GuzzleHttp\Exception\ClientException;
use unreal4u\TelegramAPI\Telegram\Methods\SendMessage;
use unreal4u\TelegramAPI\TgLog;
/**
* Service which sends simple messages to Telegram users
*/
class SimpleSender
{
/**
* @var TgLog
*/
private $client;
/**
* @param TgLog $client
*/
public function __construct(TgLog $client)
{
$this->client = $client;
}
/**
* Send simple message
*
* @param int $chatId
* @param string $text
*
* @return bool
*/
public function sendMessage(int $chatId, string $text): bool
{
$sendMessage = new SendMessage();
$sendMessage->chat_id = $chatId;
$sendMessage->text = $text;
try {
$this->client->performApiRequest($sendMessage);
return true;
} catch (ClientException $e) {
return false;
}
}
}

View file

@ -1,53 +0,0 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Twig;
use Skobkin\Bundle\PointToolsBundle\Service\UserApi;
class PointAvatarExtension extends \Twig_Extension
{
/**
* @var UserApi
*/
private $userApi;
public function __construct(UserApi $userApi)
{
$this->userApi = $userApi;
}
public function getFunctions()
{
return [
new \Twig_SimpleFunction('point_avatar', [$this, 'pointAvatarFunction']),
new \Twig_SimpleFunction('point_avatar_small', [$this, 'pointAvatarSmallFunction']),
new \Twig_SimpleFunction('point_avatar_medium', [$this, 'pointAvatarMediumFunction']),
new \Twig_SimpleFunction('point_avatar_large', [$this, 'pointAvatarLargeFunction']),
];
}
public function pointAvatarSmallFunction($login)
{
return $this->pointAvatarFunction($login, UserApi::AVATAR_SIZE_SMALL);
}
public function pointAvatarMediumFunction($login)
{
return $this->pointAvatarFunction($login, UserApi::AVATAR_SIZE_MEDIUM);
}
public function pointAvatarLargeFunction($login)
{
return $this->pointAvatarFunction($login, UserApi::AVATAR_SIZE_LARGE);
}
public function pointAvatarFunction($login, $size)
{
return $this->userApi->getAvatarUrlByLogin($login, $size);
}
public function getName()
{
return 'point_tools_avatars';
}
}

View file

@ -0,0 +1,86 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Twig;
use Skobkin\Bundle\PointToolsBundle\Service\UserApi;
class PointUserExtension extends \Twig_Extension
{
const POINT_HOST = 'point.im';
/**
* @var UserApi
*/
private $userApi;
public function __construct(UserApi $userApi)
{
$this->userApi = $userApi;
}
public function getFunctions()
{
return [
new \Twig_SimpleFunction('point_avatar', [$this, 'pointAvatarFunction']),
new \Twig_SimpleFunction('point_avatar_small', [$this, 'pointAvatarSmallFunction']),
new \Twig_SimpleFunction('point_avatar_medium', [$this, 'pointAvatarMediumFunction']),
new \Twig_SimpleFunction('point_avatar_large', [$this, 'pointAvatarLargeFunction']),
new \Twig_SimpleFunction('point_user_url', [$this, 'pointUserUrl']),
new \Twig_SimpleFunction('point_user_blog_url', [$this, 'pointUserBlogUrl']),
];
}
public function getFilters()
{
return [
new \Twig_SimpleFilter('point_avatar', [$this, 'pointAvatarFunction']),
new \Twig_SimpleFilter('point_avatar_small', [$this, 'pointAvatarSmallFunction']),
new \Twig_SimpleFilter('point_avatar_medium', [$this, 'pointAvatarMediumFunction']),
new \Twig_SimpleFilter('point_avatar_large', [$this, 'pointAvatarLargeFunction']),
new \Twig_SimpleFilter('point_user_url', [$this, 'pointUserUrl']),
new \Twig_SimpleFilter('point_user_blog_url', [$this, 'pointUserBlogUrl']),
];
}
public function pointAvatarSmallFunction(string $login): string
{
return $this->pointAvatarFunction($login, UserApi::AVATAR_SIZE_SMALL);
}
public function pointAvatarMediumFunction(string $login): string
{
return $this->pointAvatarFunction($login, UserApi::AVATAR_SIZE_MEDIUM);
}
public function pointAvatarLargeFunction(string $login): string
{
return $this->pointAvatarFunction($login, UserApi::AVATAR_SIZE_LARGE);
}
public function pointAvatarFunction(string $login, $size): string
{
return $this->userApi->getAvatarUrlByLogin($login, $size);
}
/**
* @param string $login
* @param bool $forceHttps
*
* @return string
*/
public function pointUserUrl(string $login, bool $forceHttps = false): string
{
return sprintf('%s//%s.%s/', $forceHttps ? 'https' : '', $login, self::POINT_HOST);
}
/**
* @param string $login
* @param bool $forceHttps
*
* @return string
*/
public function pointUserBlogUrl(string $login, bool $forceHttps = false): string
{
return sprintf('%s//%s.%s/blog/', $forceHttps ? 'https' : '', $login, self::POINT_HOST);
}
}