Merge branch 'master' into feature_posts

This commit is contained in:
Alexey Skobkin 2015-06-02 10:56:29 +03:00
commit ca28ebd67d
13 changed files with 349 additions and 213 deletions

54
README.md Normal file
View file

@ -0,0 +1,54 @@
# Point Tools
Point Tools - это сервис предоставляющий дополнительные функции для блогов [Point.im](https://point.im/).
# Установка
Установка сервиса довольно проста:
## Получение исходников
```shell
git clone https://skobkin@bitbucket.org/skobkin/point-tools.git
cd point-tools
```
## Выставление прав
Выставьте права на запись для директорий `app/cache` и `app/logs`.
## Установка зависимостей
```shell
# В dev-среде:
composer install
# В prod-среде
composer install --no-dev --optimize-autoloader
```
После установки зависимостей у вас будут запрошены реквизиты доступа к БД PostgreSQL и данные необходимые для функционирования сервиса.
## Инициализация БД
```shell
php app/console doctrine:migrations:migrate
```
## Установка ресурсов
```shell
php app/console assets:install web --symlink
```
## Добавление задания в CRON
```shell
crontab -e
```
Вставьте в ваш файл crontab конфиг задания:
```crontab
# point.skobk.in
*/10 * * * * /usr/bin/php /path/to/point-tools/app/console point:update:subscriptions --env=prod
```

View file

@ -27,6 +27,9 @@
<li><a href="{{ path('index') }}"><span class="glyphicon glyphicon-home"></span> {{ 'Main'|trans }}</a></li>
<li><a href="{{ path('users_top') }}"><span class="glyphicon glyphicon-stats"></span> {{ 'Top'|trans }}</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="https://bitbucket.org/skobkin/point-tools/issues?status=new&status=open" target="_blank"><span class="glyphicon glyphicon-envelope"></span> {{ 'Report a bug'|trans }}</a></li>
</ul>
{% endblock %}
</div>
{%- endblock -%}
@ -42,11 +45,16 @@
{% block footer %}
<div class="row">
<div class="copyright col-sm-6 col-xs-12">
<div class="copyright col-xs-8">
<p>
&copy; 2015{% if 2015 != 'now'|date('Y') %}-{{ 'now'|date('Y') }}{% endif %}
<a href="https://skobk.in/" target="_blank">Alexey Skobkin</a> aka <a href="https://skobkin-ru.point.im/" target="_blank">@skobkin-ru</a>
</p>
</div>
<div class="powered-by col-xs-4">
<p class="pull-right">
<a href="https://bitbucket.org/skobkin/point-tools" target="_blank"><span class="glyphicon glyphicon-download-alt"></span> {{ 'Source code'|trans }}</a>
</p>
</div>
</div>
{% endblock %}

View file

@ -542,11 +542,22 @@ class SymfonyRequirements extends RequirementCollection
/* optional recommendations follow */
$this->addRecommendation(
file_get_contents(__FILE__) === file_get_contents(__DIR__.'/../vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Resources/skeleton/app/SymfonyRequirements.php'),
'Requirements file should be up-to-date',
'Your requirements file is outdated. Run composer install and re-check your configuration.'
);
if (file_exists(__DIR__.'/../vendor/composer')) {
require_once __DIR__.'/../vendor/autoload.php';
try {
$r = new \ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle');
$contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php');
} catch (\ReflectionException $e) {
$contents = '';
}
$this->addRecommendation(
file_get_contents(__FILE__) === $contents,
'Requirements file should be up-to-date',
'Your requirements file is outdated. Run composer install and re-check your configuration.'
);
}
$this->addRecommendation(
version_compare($installedPhpVersion, '5.3.4', '>='),

View file

@ -5,7 +5,7 @@ imports:
framework:
#esi: ~
#translator: { fallbacks: ["%locale%"] }
translator: { fallbacks: ["%locale%"] }
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"

View file

@ -16,6 +16,7 @@ parameters:
point_api_base_url: https://point.im/api/
point_use_https: true
point_login: point-tools
point_id: 435
locale: en

224
composer.lock generated
View file

@ -1,23 +1,23 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at http://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"
],
"hash": "6f8a78a0b471fceb335f2e83e43985ef",
"packages": [
{
"name": "doctrine/annotations",
"version": "v1.2.3",
"version": "v1.2.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "eeda578cbe24a170331a1cfdf78be723412df7a4"
"reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/eeda578cbe24a170331a1cfdf78be723412df7a4",
"reference": "eeda578cbe24a170331a1cfdf78be723412df7a4",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/b5202eb9e83f8db52e0e58867e0a46e63be8332e",
"reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e",
"shasum": ""
},
"require": {
@ -72,20 +72,20 @@
"docblock",
"parser"
],
"time": "2014-12-20 20:49:38"
"time": "2014-12-23 22:40:37"
},
{
"name": "doctrine/cache",
"version": "v1.4.0",
"version": "v1.4.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8"
"reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8",
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8",
"url": "https://api.github.com/repos/doctrine/cache/zipball/c9eadeb743ac6199f7eec423cb9426bc518b7b03",
"reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03",
"shasum": ""
},
"require": {
@ -96,13 +96,13 @@
},
"require-dev": {
"phpunit/phpunit": ">=3.7",
"predis/predis": "~0.8",
"predis/predis": "~1.0",
"satooshi/php-coveralls": "~0.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
"dev-master": "1.5.x-dev"
}
},
"autoload": {
@ -142,25 +142,28 @@
"cache",
"caching"
],
"time": "2015-01-15 20:38:55"
"time": "2015-04-15 00:11:59"
},
{
"name": "doctrine/collections",
"version": "v1.2",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/collections.git",
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
"url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
@ -177,17 +180,6 @@
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/",
"role": "Creator"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
@ -196,11 +188,17 @@
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
"email": "schmittjoh@gmail.com"
}
],
"description": "Collections Abstraction library",
@ -210,20 +208,20 @@
"collections",
"iterator"
],
"time": "2014-02-03 23:07:43"
"time": "2015-04-14 22:21:58"
},
{
"name": "doctrine/common",
"version": "v2.4.2",
"version": "v2.5.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common.git",
"reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b"
"reference": "cd8daf2501e10c63dced7b8b9b905844316ae9d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/common/zipball/5db6ab40e4c531f14dad4ca96a394dfce5d4255b",
"reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b",
"url": "https://api.github.com/repos/doctrine/common/zipball/cd8daf2501e10c63dced7b8b9b905844316ae9d3",
"reference": "cd8daf2501e10c63dced7b8b9b905844316ae9d3",
"shasum": ""
},
"require": {
@ -240,7 +238,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.4.x-dev"
"dev-master": "2.6.x-dev"
}
},
"autoload": {
@ -253,17 +251,6 @@
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/",
"role": "Creator"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
@ -272,11 +259,17 @@
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
"email": "schmittjoh@gmail.com"
}
],
"description": "Common Library for Doctrine projects",
@ -288,7 +281,7 @@
"persistence",
"spl"
],
"time": "2014-05-21 19:28:51"
"time": "2015-04-02 19:55:44"
},
{
"name": "doctrine/dbal",
@ -355,16 +348,16 @@
},
{
"name": "doctrine/doctrine-bundle",
"version": "v1.4.0",
"version": "v1.5.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/DoctrineBundle.git",
"reference": "1986ff3a945b584c6505d07eae92d77e41131078"
"reference": "0b9e27037c4fdbad515ee5ec89842e9091a6480f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/1986ff3a945b584c6505d07eae92d77e41131078",
"reference": "1986ff3a945b584c6505d07eae92d77e41131078",
"url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/0b9e27037c4fdbad515ee5ec89842e9091a6480f",
"reference": "0b9e27037c4fdbad515ee5ec89842e9091a6480f",
"shasum": ""
},
"require": {
@ -372,6 +365,7 @@
"doctrine/doctrine-cache-bundle": "~1.0",
"jdorn/sql-formatter": "~1.1",
"php": ">=5.3.2",
"symfony/console": "~2.3",
"symfony/doctrine-bridge": "~2.2",
"symfony/framework-bundle": "~2.3"
},
@ -390,7 +384,7 @@
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
"dev-master": "1.5.x-dev"
}
},
"autoload": {
@ -428,7 +422,7 @@
"orm",
"persistence"
],
"time": "2015-02-28 11:04:45"
"time": "2015-05-28 12:27:15"
},
{
"name": "doctrine/doctrine-cache-bundle",
@ -521,19 +515,19 @@
"source": {
"type": "git",
"url": "https://github.com/doctrine/DoctrineMigrationsBundle.git",
"reference": "6a1bd731dbdd4ad952a3b246a8f38c9c12f52e62"
"reference": "1e8cd4415bd2f893eb828216b529a75e8b61d579"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/6a1bd731dbdd4ad952a3b246a8f38c9c12f52e62",
"reference": "6a1bd731dbdd4ad952a3b246a8f38c9c12f52e62",
"url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/1e8cd4415bd2f893eb828216b529a75e8b61d579",
"reference": "1e8cd4415bd2f893eb828216b529a75e8b61d579",
"shasum": ""
},
"require": {
"doctrine/doctrine-bundle": "~1.0",
"doctrine/migrations": "~1.0@dev",
"php": ">=5.3.2",
"symfony/framework-bundle": "~2.1"
"symfony/framework-bundle": "~2.3|~3.0"
},
"type": "symfony-bundle",
"extra": {
@ -571,7 +565,7 @@
"migrations",
"schema"
],
"time": "2015-02-16 13:24:46"
"time": "2015-05-06 08:32:15"
},
{
"name": "doctrine/inflector",
@ -700,21 +694,28 @@
"source": {
"type": "git",
"url": "https://github.com/doctrine/migrations.git",
"reference": "65978aa4e9ffca3bb632225ad8c6320077d80d85"
"reference": "abb87d84ed21fd30c27bd3b52252a495a36d32fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/migrations/zipball/65978aa4e9ffca3bb632225ad8c6320077d80d85",
"reference": "65978aa4e9ffca3bb632225ad8c6320077d80d85",
"url": "https://api.github.com/repos/doctrine/migrations/zipball/abb87d84ed21fd30c27bd3b52252a495a36d32fb",
"reference": "abb87d84ed21fd30c27bd3b52252a495a36d32fb",
"shasum": ""
},
"require": {
"doctrine/dbal": "~2.0",
"php": ">=5.3.2"
"php": ">=5.3.2",
"symfony/console": "~2.3",
"symfony/yaml": "~2.3"
},
"conflict": {
"doctrine/orm": "<2.4"
},
"require-dev": {
"symfony/console": "2.*",
"symfony/yaml": "2.*"
"doctrine/coding-standard": "dev-master",
"doctrine/orm": "2.*",
"phpunit/phpunit": "~4.0",
"satooshi/php-coveralls": "0.6.*"
},
"suggest": {
"symfony/console": "to run the migration from the console"
@ -750,7 +751,7 @@
"database",
"migrations"
],
"time": "2015-03-23 09:47:20"
"time": "2015-05-26 15:30:26"
},
{
"name": "doctrine/orm",
@ -1281,17 +1282,17 @@
},
{
"name": "sensio/distribution-bundle",
"version": "v3.0.20",
"version": "v3.0.25",
"target-dir": "Sensio/Bundle/DistributionBundle",
"source": {
"type": "git",
"url": "https://github.com/sensiolabs/SensioDistributionBundle.git",
"reference": "48c76189fb0a76a20a4a67a750b513ed06074b55"
"reference": "01931139b0f067a4016d5d56e82c2b3086533b89"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sensiolabs/SensioDistributionBundle/zipball/48c76189fb0a76a20a4a67a750b513ed06074b55",
"reference": "48c76189fb0a76a20a4a67a750b513ed06074b55",
"url": "https://api.github.com/repos/sensiolabs/SensioDistributionBundle/zipball/01931139b0f067a4016d5d56e82c2b3086533b89",
"reference": "01931139b0f067a4016d5d56e82c2b3086533b89",
"shasum": ""
},
"require": {
@ -1337,21 +1338,20 @@
"configuration",
"distribution"
],
"time": "2015-03-26 11:09:50"
"time": "2015-05-29 22:35:41"
},
{
"name": "sensio/framework-extra-bundle",
"version": "v3.0.6",
"target-dir": "Sensio/Bundle/FrameworkExtraBundle",
"version": "v3.0.8",
"source": {
"type": "git",
"url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git",
"reference": "1c3ed356bd1ff67cd71806efbb71511644035c85"
"reference": "a30fc18bf147bc25faf6b1d54bf55cfad4b63cba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/1c3ed356bd1ff67cd71806efbb71511644035c85",
"reference": "1c3ed356bd1ff67cd71806efbb71511644035c85",
"url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/a30fc18bf147bc25faf6b1d54bf55cfad4b63cba",
"reference": "a30fc18bf147bc25faf6b1d54bf55cfad4b63cba",
"shasum": ""
},
"require": {
@ -1364,6 +1364,7 @@
},
"suggest": {
"symfony/expression-language": "",
"symfony/psr-http-message-bridge": "To use the PSR-7 converters",
"symfony/security-bundle": ""
},
"type": "symfony-bundle",
@ -1373,8 +1374,8 @@
}
},
"autoload": {
"psr-0": {
"Sensio\\Bundle\\FrameworkExtraBundle": ""
"psr-4": {
"Sensio\\Bundle\\FrameworkExtraBundle\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@ -1392,20 +1393,20 @@
"annotations",
"controllers"
],
"time": "2015-03-24 15:12:07"
"time": "2015-05-29 18:27:23"
},
{
"name": "sensiolabs/security-checker",
"version": "v2.0.1",
"version": "v2.0.5",
"source": {
"type": "git",
"url": "https://github.com/sensiolabs/security-checker.git",
"reference": "134cecf1c61256bd8e973e11376891a724543820"
"reference": "2c2a71f1c77d9765c12638c4724d9ca23658a810"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/134cecf1c61256bd8e973e11376891a724543820",
"reference": "134cecf1c61256bd8e973e11376891a724543820",
"url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/2c2a71f1c77d9765c12638c4724d9ca23658a810",
"reference": "2c2a71f1c77d9765c12638c4724d9ca23658a810",
"shasum": ""
},
"require": {
@ -1437,7 +1438,7 @@
}
],
"description": "A security checker for your composer.lock",
"time": "2015-01-26 16:25:19"
"time": "2015-05-28 14:22:40"
},
{
"name": "swiftmailer/swiftmailer",
@ -1678,12 +1679,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/symfony.git",
"reference": "6ce03d3942ae65b9bcbc2afbec800ea1cf8361d8"
"reference": "7493c2bef54fb818c5304bdd9d2194890b839422"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/symfony/zipball/6ce03d3942ae65b9bcbc2afbec800ea1cf8361d8",
"reference": "6ce03d3942ae65b9bcbc2afbec800ea1cf8361d8",
"url": "https://api.github.com/repos/symfony/symfony/zipball/7493c2bef54fb818c5304bdd9d2194890b839422",
"reference": "7493c2bef54fb818c5304bdd9d2194890b839422",
"shasum": ""
},
"require": {
@ -1747,7 +1748,6 @@
"ircmaxell/password-compat": "~1.0",
"monolog/monolog": "~1.11",
"ocramius/proxy-manager": "~0.4|~1.0",
"propel/propel1": "~1.6",
"symfony/phpunit-bridge": "self.version"
},
"type": "library",
@ -1757,14 +1757,14 @@
}
},
"autoload": {
"psr-0": {
"Symfony\\Bridge\\Doctrine\\": "src/",
"Symfony\\Bridge\\Monolog\\": "src/",
"Symfony\\Bridge\\ProxyManager\\": "src/",
"Symfony\\Bridge\\Swiftmailer\\": "src/",
"Symfony\\Bridge\\Twig\\": "src/",
"Symfony\\Bundle\\": "src/",
"Symfony\\Component\\": "src/"
"psr-4": {
"Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/",
"Symfony\\Bridge\\Monolog\\": "src/Symfony/Bridge/Monolog/",
"Symfony\\Bridge\\ProxyManager\\": "src/Symfony/Bridge/ProxyManager/",
"Symfony\\Bridge\\Swiftmailer\\": "src/Symfony/Bridge/Swiftmailer/",
"Symfony\\Bridge\\Twig\\": "src/Symfony/Bridge/Twig/",
"Symfony\\Bundle\\": "src/Symfony/Bundle/",
"Symfony\\Component\\": "src/Symfony/Component/"
},
"classmap": [
"src/Symfony/Component/HttpFoundation/Resources/stubs",
@ -1779,21 +1779,21 @@
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "The Symfony PHP framework",
"homepage": "http://symfony.com",
"homepage": "https://symfony.com",
"keywords": [
"framework"
],
"time": "2015-03-29 09:44:52"
"time": "2015-05-30 17:16:04"
},
{
"name": "twig/extensions",
@ -1849,20 +1849,20 @@
},
{
"name": "twig/twig",
"version": "v1.18.0",
"version": "v1.18.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf"
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/4cf7464348e7f9893a93f7096a90b73722be99cf",
"reference": "4cf7464348e7f9893a93f7096a90b73722be99cf",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/9f70492f44398e276d1b81c1b43adfe6751c7b7f",
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
"php": ">=5.2.7"
},
"type": "library",
"extra": {
@ -1902,7 +1902,7 @@
"keywords": [
"templating"
],
"time": "2015-01-25 17:32:08"
"time": "2015-04-19 08:30:27"
}
],
"packages-dev": [

View file

@ -44,8 +44,14 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
/** @var SubscriptionsManager $subscriptionsManager */
$subscriptionsManager = $this->getContainer()->get('skobkin_point_tools.subscriptions_manager');
$serviceUserName = $this->getContainer()->getParameter('point_login');
$serviceUser = $this->getContainer()->get('doctrine.orm.entity_manager')->getRepository('SkobkinPointToolsBundle:User')->findOneBy(['login' => $serviceUserName]);
try {
$serviceUserId = $this->getContainer()->getParameter('point_id');
} catch (\InvalidArgumentException $e) {
$log->alert('Could not get point_id parameter from config file', ['exception_message' => $e->getMessage()]);
return false;
}
$serviceUser = $this->getContainer()->get('doctrine.orm.entity_manager')->getRepository('SkobkinPointToolsBundle:User')->find($serviceUserId);
if (!$serviceUser) {
$log->info('Service user not found');
@ -59,16 +65,24 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
}
try {
$serviceSubscribers = $api->getUserSubscribersByLogin($serviceUserName);
$serviceSubscribers = $api->getUserSubscribersById($serviceUserId);
} catch (\Exception $e) {
// @todo fallback to the local subscribers list
$output->writeln('Error while getting service subscribers');
$log->error('Error while getting service subscribers.' . PHP_EOL .
$e->getMessage() . PHP_EOL .
$e->getFile() . ':' . $e->getLine()
);
$log->error('Error while getting service subscribers.', ['user_login' => $serviceUser->getLogin(), 'user_id' => $serviceUser->getId(), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
return false;
$serviceSubscribers = [];
foreach ($serviceUser->getSubscribers() as $subscription) {
$serviceSubscribers[] = $subscription->getSubscriber();
}
$output->writeln('Fallback to local list');
$log->error('Fallback to local list');
if (!count($serviceSubscribers)) {
$log->info('No local subscribers. Finishing.');
return false;
}
}
if ($output->isVerbose()) {
@ -79,10 +93,7 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
try {
$subscriptionsManager->updateUserSubscribers($serviceUser, $serviceSubscribers);
} catch (\Exception $e) {
$log->error('Error while updating service subscribers' . PHP_EOL .
$e->getMessage() . PHP_EOL .
$e->getFile() . ':' . $e->getLine()
);
$log->error('Error while updating service subscribers', ['user_login' => $serviceUser->getLogin(), 'user_id' => $serviceUser->getId(), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
return false;
}
@ -97,13 +108,10 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
$log->info('Processing @' . $user->getLogin());
try {
$userCurrentSubscribers = $api->getUserSubscribersByLogin($user->getLogin());
$userCurrentSubscribers = $api->getUserSubscribersById($user->getId());
} catch (\Exception $e) {
$output->writeln(' Error while getting subscribers. Skipping.');
$log->error('Error while getting subscribers.' . PHP_EOL .
$e->getMessage() . PHP_EOL .
$e->getFile() . ':' . $e->getLine()
);
$log->error('Error while getting subscribers.', ['user_login' => $user->getLogin(), 'user_id' => $user->getId(), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
continue;
}
@ -116,10 +124,7 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
// Updating user subscribers
$subscriptionsManager->updateUserSubscribers($user, $userCurrentSubscribers);
} catch (\Exception $e) {
$log->error('Error while updating user subscribers' . PHP_EOL .
$e->getMessage() . PHP_EOL .
$e->getFile() . ':' . $e->getLine()
);
$log->error('Error while updating user subscribers', ['user_login' => $user->getLogin(), 'user_id' => $user->getId(), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
}
// @todo move to the config

View file

@ -184,7 +184,7 @@ class User
/**
* Get subscribers
*
* @return ArrayCollection
* @return Subscription[]|ArrayCollection
*/
public function getSubscribers()
{

View file

@ -38,6 +38,10 @@ body > .container {
margin-top: 30px;
}
.user-subscriptions-log {
margin-top: 30px;
}
h4.panel-title a {
text-decoration: none;
}

View file

@ -0,0 +1,32 @@
# Russian language for Point tools
# Шапка
Toggle navigation: Переключить навигацию
Main: Главная
Top: Топ
Report a bug: Сообщить об ошибке
# Подвал
Source code: Исходный код
# Главная
All users: Всего пользователей
Subscribed users: Подписчиков сервиса
24 hours events: Событий за сутки
Username: Имя пользователя
Search: Поиск
# Страница пользователя
Subscribers: Подписчики
Subscriptions log: Лог подписок
User: Пользователь
Action: Действие
Date: Дата
No subscribers data found: Информация о подписчиках отсутствует
No log data found: Лог отсутствует
# Топ пользователей
Top users: Популярные пользователи
Subscribers count: Подписчиков

View file

@ -3,30 +3,30 @@
{% block content %}
<div class="well well-lg">
{# @todo rewrite to Symfony forms #}
<form class="form-inline" method="post" action="{{ url('user_search') }}">
<form class="form-inline" method="post" action="{{ path('user_search') }}">
<div class="form-group">
<label class="sr-only" for="index-input-username">Username</label>
<label class="sr-only" for="index-input-username">{{ 'Username'|trans }}</label>
<div class="input-group">
<div class="input-group-addon">@</div>
<input name="login" type="text" class="form-control" id="index-input-username" placeholder="username">
</div>
</div>
<button type="submit" class="btn btn-primary">Search</button>
<button type="submit" class="btn btn-primary">{{ 'Search'|trans }}</button>
</form>
</div>
<div class="container service-stats">
<div class="row">
<div class="col-xs-2"><span class="glyphicon glyphicon-user"></span> {{ 'All users'|trans }}</div>
<div class="col-xs-2">{{ users_count }}</div>
<div class="col-xs-8 col-sm-3"><span class="glyphicon glyphicon-user"></span> {{ 'All users'|trans }}</div>
<div class="col-xs-4 col-sm-2">{{ users_count }}</div>
</div>
<div class="row">
<div class="col-xs-2"><span class="glyphicon glyphicon-user"></span> {{ 'Subscribed users'|trans }}</div>
<div class="col-xs-2"><a href="{{ url('user_show', {'login': service_login}) }}">{{ subscribers_count }}</a></div>
<div class="col-xs-8 col-sm-3"><span class="glyphicon glyphicon-user"></span> {{ 'Subscribed users'|trans }}</div>
<div class="col-xs-4 col-sm-2"><a href="{{ url('user_show', {'login': service_login}) }}">{{ subscribers_count }}</a></div>
</div>
<div class="row">
<div class="col-xs-2"><span class="glyphicon glyphicon-list"></span> {{ 'Last events'|trans }}</div>
<div class="col-xs-2">{{ events_count }}</div>
<div class="col-xs-8 col-sm-3"><span class="glyphicon glyphicon-list"></span> {{ '24 hours events'|trans }}</div>
<div class="col-xs-4 col-sm-2">{{ events_count }}</div>
</div>
</div>
{% endblock %}

View file

@ -9,68 +9,77 @@
</h1>
<div class="user-subscribers">
<div class="panel-group" id="accordion-subscribers">
<div class="panel panel-default">
<div class="panel-heading"id="headingOne">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion-subscribers" aria-expanded="true" href="#collapse-subscribers">
<span class="glyphicon glyphicon-collapse-down"></span> {{ 'Subscribers'|trans }}
</a>
</h4>
</div>
<div id="collapse-subscribers" class="panel-collapse collapse in">
<div class="panel-body">
<ul class="users mosaic">
{% for user in subscribers %}
<li><a href="{{ url('user_show', {login: user.login}) }}">@{{ user.login }}</a></li>
{% endfor %}
</ul>
{% if subscribers|length > 0 %}
<div class="panel-group" id="accordion-subscribers">
<div class="panel panel-default">
<div class="panel-heading" id="heading-subscribers">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion-subscribers" aria-expanded="false" href="#collapse-subscribers">
<span class="glyphicon glyphicon-collapse-down"></span> {{ 'Subscribers'|trans }}
</a>
</h4>
</div>
<div id="collapse-subscribers" class="panel-collapse collapse" aria-labelledby="heading-subscribers">
<div class="panel-body">
<ul class="users mosaic">
{% for user in subscribers %}
<li><a href="{{ url('user_show', {login: user.login}) }}">@{{ user.login }}</a></li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
</div>
{% else %}
<div class="alert alert-warning" role="alert">{{ 'No subscribers data found'|trans }}</div>
{% endif %}
</div>
<div class="user-subscribers">
<div class="panel-group" id="accordion-log">
<div class="panel panel-default">
<div class="panel-heading" id="headingOne">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion-log" aria-expanded="true" href="#collapse-log">
<span class="glyphicon glyphicon-collapse-down"></span> {{ 'Subscriptions log'|trans }}
</a>
</h4>
</div>
<div id="collapse-log" class="panel-collapse collapse in">
<div class="panel-body">
<table class="table table-striped">
<thead>
<tr>
<td>{{ 'User'|trans }}</td>
<td>{{ 'Action'|trans }}</td>
<td>{{ 'Date'|trans }}</td>
</tr>
</thead>
<tbody>
{% for event in log %}
<div class="user-subscriptions-log">
{% if log|length > 0 %}
<div class="panel-group" id="accordion-log">
<div class="panel panel-default">
<div class="panel-heading" id="heading-subscriptions-log">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion-log" aria-expanded="true" href="#collapse-log">
<span class="glyphicon glyphicon-collapse-down"></span> {{ 'Subscriptions log'|trans }}
</a>
</h4>
</div>
<div id="collapse-log" class="panel-collapse collapse in" aria-labelledby="heading-subscriptions-log">
<div class="panel-body">
<table class="table table-striped">
<thead>
<tr>
<td>
<a href="{{ url('user_show', {login: event.subscriber.login}) }}">@{{ event.subscriber.login }}</a>
</td>
<td>
<span class="glyphicon {% if event.action == 'subscribe' %}glyphicon-plus{% elseif event.action == 'unsubscribe' %}glyphicon-minus{% endif %}"></span>
</td>
<td>
{# Use DateTime helper: https://sonata-project.org/bundles/intl/master/doc/reference/datetime.html #}
{{ event.date|date('H:i:s d F Y') }}
</td>
<td>{{ 'User'|trans }}</td>
<td>{{ 'Action'|trans }}</td>
<td>{{ 'Date'|trans }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for event in log %}
<tr>
<td>
<a href="{{ url('user_show', {login: event.subscriber.login}) }}">@{{ event.subscriber.login }}</a>
</td>
<td>
<span class="glyphicon {% if event.action == 'subscribe' %}glyphicon-plus{% elseif event.action == 'unsubscribe' %}glyphicon-minus{% endif %}"></span>
</td>
<td>
{# Use DateTime helper: https://sonata-project.org/bundles/intl/master/doc/reference/datetime.html #}
{{ event.date|date('d F Y H:i:s') }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% else %}
<div class="alert alert-warning" role="alert">{{ 'No log data found'|trans }}</div>
{% endif %}
</div>
{% endblock %}

View file

@ -18,6 +18,7 @@ class SubscriptionsManager
protected $em;
// @todo Add logger
public function __construct(EntityManagerInterface $entityManager)
{
$this->em = $entityManager;
@ -38,6 +39,14 @@ class SubscriptionsManager
$oldSubscribersList[] = $subscription->getSubscriber();
}
$isFirstTime = false;
// Preventing to add garbage subscriptions for first processing
// @todo improve algorithm
if ((count($oldSubscribersList) === 0) && (count($newSubscribersList) > 1)) {
$isFirstTime = true;
}
unset($tmpOldSubscribers);
$subscribedList = $this->getUsersListsDiff($newSubscribersList, $oldSubscribersList);
@ -53,17 +62,20 @@ class SubscriptionsManager
$user->addSubscriber($subscription);
$logEvent = new SubscriptionEvent();
$logEvent
->setSubscriber($subscribedUser)
->setAuthor($user)
->setAction(SubscriptionEvent::ACTION_SUBSCRIBE)
;
// If it's not first processing
if (!$isFirstTime) {
$logEvent = new SubscriptionEvent();
$logEvent
->setSubscriber($subscribedUser)
->setAuthor($user)
->setAction(SubscriptionEvent::ACTION_SUBSCRIBE);
$user->addNewSubscriberEvent($logEvent);
$user->addNewSubscriberEvent($logEvent);
$this->em->persist($logEvent);
}
$this->em->persist($subscription);
$this->em->persist($logEvent);
}
unset($subscribedList);
@ -81,7 +93,7 @@ class SubscriptionsManager
$logEvent = new SubscriptionEvent();
$logEvent
->setSubscriber($unsubscribedUser)
->setAction($user)
->setAuthor($user)
->setAction(SubscriptionEvent::ACTION_UNSUBSCRIBE)
;