#38 fix. User privacy status update implemented ('point:update:privacy' command). Small refactoring and several bug fixes. Small optimization.
This commit is contained in:
parent
013fb3ef3d
commit
fe5c936681
40
app/DoctrineMigrations/Version20171104182713.php
Normal file
40
app/DoctrineMigrations/Version20171104182713.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Application\Migrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Migrations\AbstractMigration;
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New fields for User entity: 'public' and 'whitelistOnly' (privacy support)
|
||||||
|
*/
|
||||||
|
class Version20171104182713 extends AbstractMigration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Schema $schema
|
||||||
|
*/
|
||||||
|
public function up(Schema $schema)
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
|
||||||
|
|
||||||
|
$this->addSql('ALTER TABLE users.users ADD public BOOLEAN DEFAULT FALSE NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE users.users ADD whitelist_only BOOLEAN DEFAULT FALSE NOT NULL');
|
||||||
|
$this->addSql('CREATE INDEX idx_user_public ON users.users (public)');
|
||||||
|
$this->addSql('CREATE INDEX idx_user_removed ON users.users (is_removed)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Schema $schema
|
||||||
|
*/
|
||||||
|
public function down(Schema $schema)
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
|
||||||
|
|
||||||
|
$this->addSql('DROP INDEX users.idx_user_public');
|
||||||
|
$this->addSql('DROP INDEX users.idx_user_removed');
|
||||||
|
$this->addSql('ALTER TABLE users.users DROP public');
|
||||||
|
$this->addSql('ALTER TABLE users.users DROP whitelist_only');
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,8 +38,10 @@ class RestoreRemovedUsersCommand extends Command
|
||||||
*/
|
*/
|
||||||
private $delay;
|
private $delay;
|
||||||
|
|
||||||
public function setDependencies(LoggerInterface $logger, EntityManagerInterface $em, UserRepository $userRepo, UserApi $userApi, int $delay): void
|
public function __construct(LoggerInterface $logger, EntityManagerInterface $em, UserRepository $userRepo, UserApi $userApi, int $delay)
|
||||||
{
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
|
@ -77,6 +79,8 @@ class RestoreRemovedUsersCommand extends Command
|
||||||
'login' => $removedUser->getLogin(),
|
'login' => $removedUser->getLogin(),
|
||||||
]);
|
]);
|
||||||
$removedUser->restore();
|
$removedUser->restore();
|
||||||
|
|
||||||
|
$this->em->flush();
|
||||||
}
|
}
|
||||||
} catch (UserNotFoundException $e) {
|
} catch (UserNotFoundException $e) {
|
||||||
$this->logger->debug('User is really removed. Keep going.', [
|
$this->logger->debug('User is really removed. Keep going.', [
|
||||||
|
|
|
@ -4,16 +4,13 @@ namespace Skobkin\Bundle\PointToolsBundle\Command;
|
||||||
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Skobkin\Bundle\PointToolsBundle\Entity\Subscription;
|
use Skobkin\Bundle\PointToolsBundle\Entity\{Subscription, User};
|
||||||
use Skobkin\Bundle\PointToolsBundle\Entity\User;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\UserNotFoundException;
|
use Skobkin\Bundle\PointToolsBundle\Exception\Api\UserNotFoundException;
|
||||||
use Skobkin\Bundle\PointToolsBundle\Repository\UserRepository;
|
use Skobkin\Bundle\PointToolsBundle\Repository\UserRepository;
|
||||||
use Skobkin\Bundle\PointToolsBundle\Service\SubscriptionsManager;
|
use Skobkin\Bundle\PointToolsBundle\Service\{SubscriptionsManager, Api\UserApi};
|
||||||
use Skobkin\Bundle\PointToolsBundle\Service\Api\UserApi;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||||
use Symfony\Component\Console\Helper\ProgressBar;
|
use Symfony\Component\Console\Helper\ProgressBar;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\{InputInterface, InputOption};
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +48,11 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
|
||||||
*/
|
*/
|
||||||
private $apiDelay = 500000;
|
private $apiDelay = 500000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $appUserId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var SubscriptionsManager
|
* @var SubscriptionsManager
|
||||||
*/
|
*/
|
||||||
|
@ -61,19 +63,24 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
|
||||||
*/
|
*/
|
||||||
private $progress;
|
private $progress;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
EntityManagerInterface $em,
|
||||||
|
LoggerInterface $logger,
|
||||||
|
UserRepository $userRepo,
|
||||||
|
UserApi $api,
|
||||||
|
SubscriptionsManager $subscriptionManager,
|
||||||
|
int $apiDelay,
|
||||||
|
int $appUserId
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
public function setDeps(LoggerInterface $logger, EntityManagerInterface $em, UserRepository $userRepo, UserApi $userApi, SubscriptionsManager $subscriptionsManager): void
|
|
||||||
{
|
|
||||||
$this->logger = $logger;
|
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
|
$this->logger = $logger;
|
||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
$this->api = $userApi;
|
$this->api = $api;
|
||||||
$this->subscriptionManager = $subscriptionsManager;
|
$this->subscriptionManager = $subscriptionManager;
|
||||||
}
|
$this->apiDelay = $apiDelay;
|
||||||
|
$this->appUserId = $appUserId;
|
||||||
public function setApiDelay(int $microSecs): void
|
|
||||||
{
|
|
||||||
$this->apiDelay = $microSecs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function configure()
|
protected function configure()
|
||||||
|
@ -96,35 +103,21 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param InputInterface $input
|
|
||||||
* @param OutputInterface $output
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$this->input = $input;
|
$this->input = $input;
|
||||||
|
|
||||||
$this->logger->debug('UpdateSubscriptionsCommand started.');
|
$this->logger->debug('UpdateSubscriptionsCommand started.');
|
||||||
|
|
||||||
try {
|
|
||||||
$appUserId = $this->getContainer()->getParameter('point_id');
|
|
||||||
} catch (\InvalidArgumentException $e) {
|
|
||||||
$this->logger->alert('Could not get point_id parameter from config file', ['exception_message' => $e->getMessage()]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->progress = new ProgressBar($output);
|
$this->progress = new ProgressBar($output);
|
||||||
$this->progress->setFormat('debug');
|
$this->progress->setFormat('debug');
|
||||||
|
|
||||||
// Beginning transaction for all changes
|
if ($input->getOption('check-only')) { // Beginning transaction for all changes
|
||||||
$this->em->beginTransaction();
|
$this->em->beginTransaction();
|
||||||
|
}
|
||||||
$this->progress->setMessage('Getting service subscribers');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$usersForUpdate = $this->getUsersForUpdate($appUserId);
|
$usersForUpdate = $this->getUsersForUpdate();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->logger->error('Error while getting service subscribers', ['exception' => get_class($e), 'message' => $e->getMessage()]);
|
$this->logger->error('Error while getting service subscribers', ['exception' => get_class($e), 'message' => $e->getMessage()]);
|
||||||
|
|
||||||
|
@ -138,78 +131,75 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->info('Processing users subscribers');
|
$this->logger->info('Processing users subscribers');
|
||||||
$this->progress->setMessage('Processing users subscribers');
|
|
||||||
$this->progress->start(count($usersForUpdate));
|
$this->progress->start(count($usersForUpdate));
|
||||||
|
|
||||||
$this->updateUsersSubscribers($usersForUpdate);
|
foreach ($usersForUpdate as $user) {
|
||||||
|
usleep($this->apiDelay);
|
||||||
|
|
||||||
|
$this->progress->advance();
|
||||||
|
$this->logger->info('Processing @'.$user->getLogin());
|
||||||
|
|
||||||
|
$this->updateUser($user);
|
||||||
|
}
|
||||||
|
|
||||||
$this->progress->finish();
|
$this->progress->finish();
|
||||||
|
|
||||||
// Flushing all changes at once to database
|
|
||||||
$this->em->flush();
|
if ($input->getOption('check-only')) { // Flushing all changes at once to the database
|
||||||
$this->em->commit();
|
$this->em->flush();
|
||||||
|
$this->em->commit();
|
||||||
|
}
|
||||||
|
|
||||||
$this->logger->debug('Finished');
|
$this->logger->debug('Finished');
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function updateUser(User $user): void
|
||||||
* @param User[] $users
|
|
||||||
*/
|
|
||||||
private function updateUsersSubscribers(array $users): void
|
|
||||||
{
|
{
|
||||||
// Updating users subscribers
|
try {
|
||||||
foreach ($users as $user) {
|
$userCurrentSubscribers = $this->api->getUserSubscribersById($user->getId());
|
||||||
usleep($this->apiDelay);
|
} catch (UserNotFoundException $e) {
|
||||||
|
$this->logger->warning('User not found. Marking as removed.', ['login' => $user->getLogin(), 'user_id' => $user->getId()]);
|
||||||
|
|
||||||
$this->progress->advance();
|
$user->markAsRemoved();
|
||||||
|
|
||||||
$this->logger->info('Processing @'.$user->getLogin());
|
return;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error(
|
||||||
|
'Error while getting subscribers. Skipping.',
|
||||||
|
[
|
||||||
|
'user_login' => $user->getLogin(),
|
||||||
|
'user_id' => $user->getId(),
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
return;
|
||||||
$userCurrentSubscribers = $this->api->getUserSubscribersById($user->getId());
|
}
|
||||||
} catch (UserNotFoundException $e) {
|
|
||||||
$this->logger->warning('User not found. Marking as removed', ['login' => $user->getLogin(), 'user_id' => $user->getId()]);
|
|
||||||
$user->markAsRemoved();
|
|
||||||
|
|
||||||
continue;
|
$this->logger->debug('Updating user subscribers');
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->logger->error(
|
|
||||||
'Error while getting subscribers. Skipping.',
|
|
||||||
[
|
|
||||||
'user_login' => $user->getLogin(),
|
|
||||||
'user_id' => $user->getId(),
|
|
||||||
'message' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
continue;
|
try {
|
||||||
}
|
// Updating user subscribers
|
||||||
|
$this->subscriptionManager->updateUserSubscribers($user, $userCurrentSubscribers);
|
||||||
$this->logger->debug('Updating user subscribers');
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error(
|
||||||
try {
|
'Error while updating user subscribers',
|
||||||
// Updating user subscribers
|
[
|
||||||
$this->subscriptionManager->updateUserSubscribers($user, $userCurrentSubscribers);
|
'user_login' => $user->getLogin(),
|
||||||
} catch (\Exception $e) {
|
'user_id' => $user->getId(),
|
||||||
$this->logger->error(
|
'message' => $e->getMessage(),
|
||||||
'Error while updating user subscribers',
|
'file' => $e->getFile(),
|
||||||
[
|
'line' => $e->getLine(),
|
||||||
'user_login' => $user->getLogin(),
|
]
|
||||||
'user_id' => $user->getId(),
|
);
|
||||||
'message' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUsersForUpdate(int $appUserId): array
|
private function getUsersForUpdate(): array
|
||||||
{
|
{
|
||||||
$usersForUpdate = [];
|
$usersForUpdate = [];
|
||||||
|
|
||||||
|
@ -218,7 +208,7 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
|
||||||
} else {
|
} else {
|
||||||
/** @var User $serviceUser */
|
/** @var User $serviceUser */
|
||||||
try {
|
try {
|
||||||
$serviceUser = $this->userRepo->findActiveUserWithSubscribers($appUserId);
|
$serviceUser = $this->userRepo->findActiveUserWithSubscribers($this->appUserId);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->logger->error('Error while getting active user with subscribers', ['app_user_id' => $appUserId]);
|
$this->logger->error('Error while getting active user with subscribers', ['app_user_id' => $appUserId]);
|
||||||
|
|
||||||
|
@ -235,7 +225,7 @@ class UpdateSubscriptionsCommand extends ContainerAwareCommand
|
||||||
$this->logger->info('Getting service subscribers');
|
$this->logger->info('Getting service subscribers');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$usersForUpdate = $this->api->getUserSubscribersById($appUserId);
|
$usersForUpdate = $this->api->getUserSubscribersById($this->appUserId);
|
||||||
} catch (UserNotFoundException $e) {
|
} catch (UserNotFoundException $e) {
|
||||||
$this->logger->critical('Service user deleted or API response is invalid');
|
$this->logger->critical('Service user deleted or API response is invalid');
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Skobkin\Bundle\PointToolsBundle\Command;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Skobkin\Bundle\PointToolsBundle\Entity\{Subscription, User};
|
||||||
|
use Skobkin\Bundle\PointToolsBundle\Exception\Api\{ForbiddenException, UserNotFoundException};
|
||||||
|
use Skobkin\Bundle\PointToolsBundle\Repository\UserRepository;
|
||||||
|
use Skobkin\Bundle\PointToolsBundle\Service\Api\UserApi;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||||
|
use Symfony\Component\Console\Helper\ProgressBar;
|
||||||
|
use Symfony\Component\Console\Input\{InputInterface, InputOption};
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
class UpdateUsersPrivacyCommand extends ContainerAwareCommand
|
||||||
|
{
|
||||||
|
/** @var EntityManagerInterface */
|
||||||
|
private $em;
|
||||||
|
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
/** @var UserRepository */
|
||||||
|
private $userRepo;
|
||||||
|
|
||||||
|
/** @var InputInterface */
|
||||||
|
private $input;
|
||||||
|
|
||||||
|
/** @var UserApi */
|
||||||
|
private $api;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $apiDelay = 500000;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $appUserId;
|
||||||
|
|
||||||
|
/** @var ProgressBar */
|
||||||
|
private $progress;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em, LoggerInterface $logger, UserRepository $userRepo, UserApi $api, int $apiDelay, int $appUserId)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->em = $em;
|
||||||
|
$this->logger = $logger;
|
||||||
|
$this->userRepo = $userRepo;
|
||||||
|
$this->api = $api;
|
||||||
|
$this->apiDelay = $apiDelay;
|
||||||
|
$this->appUserId = $appUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('point:update:privacy')
|
||||||
|
->setDescription('Update users privacy')
|
||||||
|
->addOption(
|
||||||
|
'all-users',
|
||||||
|
null,
|
||||||
|
InputOption::VALUE_NONE,
|
||||||
|
'If set, command will check all users instead of service subscribers only'
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$this->input = $input;
|
||||||
|
|
||||||
|
$this->logger->debug(static::class.' started.');
|
||||||
|
|
||||||
|
$this->progress = new ProgressBar($output);
|
||||||
|
$this->progress->setFormat('debug');
|
||||||
|
|
||||||
|
try {
|
||||||
|
/** @var User[] $usersForUpdate */
|
||||||
|
$usersForUpdate = $this->getUsersForUpdate();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error('Error while getting service subscribers', ['exception' => get_class($e), 'message' => $e->getMessage()]);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->info('Processing users privacy.');
|
||||||
|
|
||||||
|
$this->progress->start(count($usersForUpdate));
|
||||||
|
|
||||||
|
foreach ($usersForUpdate as $idx => $user) {
|
||||||
|
usleep($this->apiDelay);
|
||||||
|
|
||||||
|
$this->progress->advance();
|
||||||
|
$this->logger->info('Processing @'.$user->getLogin());
|
||||||
|
|
||||||
|
$this->updateUser($user);
|
||||||
|
|
||||||
|
// Flushing each 10 users
|
||||||
|
if (0 === $idx % 10) {
|
||||||
|
$this->em->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->progress->finish();
|
||||||
|
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->logger->debug('Finished');
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateUser(User $user): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$remoteUser = $this->api->getUserById($user->getId());
|
||||||
|
|
||||||
|
if ($remoteUser !== $user) {
|
||||||
|
$this->logger->error('Remote user is not equal with local.', ['user_id' => $user->getId(), 'user_login' => $user->getLogin()]);
|
||||||
|
}
|
||||||
|
} catch (UserNotFoundException $e) {
|
||||||
|
$this->logger->info('User not found. Marking as removed.', ['user_id' => $user->getId(), 'user_login' => $user->getLogin()]);
|
||||||
|
|
||||||
|
$user->markAsRemoved();
|
||||||
|
} catch (ForbiddenException $e) {
|
||||||
|
$this->logger->info('User profile access forbidden', ['user_id' => $user->getId(), 'user_login' => $user->getLogin()]);
|
||||||
|
|
||||||
|
$user->updatePrivacy(false, true);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error(
|
||||||
|
'Error while updating user privacy',
|
||||||
|
[
|
||||||
|
'user_login' => $user->getLogin(),
|
||||||
|
'user_id' => $user->getId(),
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUsersForUpdate(): array
|
||||||
|
{
|
||||||
|
if ($this->input->getOption('all-users')) {
|
||||||
|
return $this->userRepo->findBy(['removed' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var User $serviceUser */
|
||||||
|
try {
|
||||||
|
$serviceUser = $this->userRepo->findActiveUserWithSubscribers($this->appUserId);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error('Error while getting active user with subscribers', ['app_user_id' => $this->appUserId]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$serviceUser) {
|
||||||
|
$this->logger->critical('Service user not found or marked as removed');
|
||||||
|
|
||||||
|
throw new \RuntimeException('Service user not found in the database');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->info('Getting service subscribers');
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $this->api->getUserSubscribersById($this->appUserId);
|
||||||
|
} catch (UserNotFoundException $e) {
|
||||||
|
$this->logger->critical('Service user deleted or API response is invalid');
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->warning(
|
||||||
|
'Error while getting service subscribers. Fallback to local list.',
|
||||||
|
[
|
||||||
|
'user_login' => $serviceUser->getLogin(),
|
||||||
|
'user_id' => $serviceUser->getId(),
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$localSubscribers = [];
|
||||||
|
|
||||||
|
/** @var Subscription $subscription */
|
||||||
|
foreach ($serviceUser->getSubscribers() as $subscription) {
|
||||||
|
$localSubscribers[] = $subscription->getSubscriber();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $localSubscribers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
namespace Skobkin\Bundle\PointToolsBundle\Controller\Api;
|
namespace Skobkin\Bundle\PointToolsBundle\Controller\Api;
|
||||||
|
|
||||||
|
use Skobkin\Bundle\PointToolsBundle\DTO\Api\PostsPage;
|
||||||
use Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs\PostFactory;
|
use Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs\PostFactory;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\{Request, Response};
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
|
|
||||||
class CrawlerController extends AbstractApiController
|
class CrawlerController extends AbstractApiController
|
||||||
{
|
{
|
||||||
|
@ -21,7 +21,7 @@ class CrawlerController extends AbstractApiController
|
||||||
|
|
||||||
$serializer = $this->get('jms_serializer');
|
$serializer = $this->get('jms_serializer');
|
||||||
|
|
||||||
$page = $serializer->deserialize($json, 'Skobkin\Bundle\PointToolsBundle\DTO\Api\PostsPage', 'json');
|
$page = $serializer->deserialize($json, PostsPage::class, 'json');
|
||||||
|
|
||||||
/** @var PostFactory $factory */
|
/** @var PostFactory $factory */
|
||||||
$factory = $this->get('app.point.post_factory');
|
$factory = $this->get('app.point.post_factory');
|
||||||
|
|
|
@ -6,15 +6,18 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Table(name="users", schema="users")
|
* @ORM\Table(name="users", schema="users", indexes={
|
||||||
|
* @ORM\Index(name="idx_user_public", columns={"public"}),
|
||||||
|
* @ORM\Index(name="idx_user_removed", columns={"is_removed"})
|
||||||
|
* })
|
||||||
* @ORM\Entity(repositoryClass="Skobkin\Bundle\PointToolsBundle\Repository\UserRepository")
|
* @ORM\Entity(repositoryClass="Skobkin\Bundle\PointToolsBundle\Repository\UserRepository")
|
||||||
* @ORM\HasLifecycleCallbacks
|
* @ORM\HasLifecycleCallbacks
|
||||||
*/
|
*/
|
||||||
class User
|
class User
|
||||||
{
|
{
|
||||||
const AVATAR_SIZE_SMALL = '24';
|
public const AVATAR_SIZE_SMALL = '24';
|
||||||
const AVATAR_SIZE_MEDIUM = '40';
|
public const AVATAR_SIZE_MEDIUM = '40';
|
||||||
const AVATAR_SIZE_LARGE = '80';
|
public const AVATAR_SIZE_LARGE = '80';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
|
@ -52,6 +55,20 @@ class User
|
||||||
*/
|
*/
|
||||||
private $updatedAt;
|
private $updatedAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*
|
||||||
|
* @ORM\Column(name="public", type="boolean", nullable=false, options={"default": false})
|
||||||
|
*/
|
||||||
|
private $public = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*
|
||||||
|
* @ORM\Column(name="whitelist_only", type="boolean", nullable=false, options={"default": false})
|
||||||
|
*/
|
||||||
|
private $whitelistOnly = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ArrayCollection|Subscription[]
|
* @var ArrayCollection|Subscription[]
|
||||||
*
|
*
|
||||||
|
@ -140,7 +157,7 @@ class User
|
||||||
/**
|
/**
|
||||||
* @return Subscription[]|ArrayCollection
|
* @return Subscription[]|ArrayCollection
|
||||||
*/
|
*/
|
||||||
public function getSubscribers(): iterable
|
public function getSubscribers(): ArrayCollection
|
||||||
{
|
{
|
||||||
return $this->subscribers;
|
return $this->subscribers;
|
||||||
}
|
}
|
||||||
|
@ -148,7 +165,7 @@ class User
|
||||||
/**
|
/**
|
||||||
* @return Subscription[]|ArrayCollection
|
* @return Subscription[]|ArrayCollection
|
||||||
*/
|
*/
|
||||||
public function getSubscriptions(): iterable
|
public function getSubscriptions(): ArrayCollection
|
||||||
{
|
{
|
||||||
return $this->subscriptions;
|
return $this->subscriptions;
|
||||||
}
|
}
|
||||||
|
@ -163,7 +180,7 @@ class User
|
||||||
/**
|
/**
|
||||||
* @return SubscriptionEvent[]|ArrayCollection
|
* @return SubscriptionEvent[]|ArrayCollection
|
||||||
*/
|
*/
|
||||||
public function getNewSubscriberEvents(): iterable
|
public function getNewSubscriberEvents(): ArrayCollection
|
||||||
{
|
{
|
||||||
return $this->newSubscriberEvents;
|
return $this->newSubscriberEvents;
|
||||||
}
|
}
|
||||||
|
@ -178,6 +195,22 @@ class User
|
||||||
return $this->updatedAt;
|
return $this->updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updatePrivacy(?bool $public, ?bool $whitelistOnly): void
|
||||||
|
{
|
||||||
|
$this->public = $public;
|
||||||
|
$this->whitelistOnly = $whitelistOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isPublic(): ?bool
|
||||||
|
{
|
||||||
|
return $this->public;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isWhitelistOnly(): ?bool
|
||||||
|
{
|
||||||
|
return $this->whitelistOnly;
|
||||||
|
}
|
||||||
|
|
||||||
public function isRemoved(): bool
|
public function isRemoved(): bool
|
||||||
{
|
{
|
||||||
return $this->removed;
|
return $this->removed;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Skobkin\Bundle\PointToolsBundle\Exception\Api;
|
namespace Skobkin\Bundle\PointToolsBundle\Exception\Api;
|
||||||
|
|
||||||
class UserNotFoundException extends ApiException
|
class UserNotFoundException extends NotFoundException
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
|
@ -22,6 +22,7 @@ class UserNotFoundException extends ApiException
|
||||||
public function __construct($message = 'User not found', $code = 0, \Exception $previous = null, $userId = null, $login = null)
|
public function __construct($message = 'User not found', $code = 0, \Exception $previous = null, $userId = null, $login = null)
|
||||||
{
|
{
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct($message, $code, $previous);
|
||||||
|
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
$this->login = $login;
|
$this->login = $login;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ class UserRepository extends EntityRepository
|
||||||
{
|
{
|
||||||
$qb = $this->createQueryBuilder('u');
|
$qb = $this->createQueryBuilder('u');
|
||||||
|
|
||||||
// May be optimize hydration procedure
|
// @todo May be optimize hydration procedure
|
||||||
return $qb
|
return $qb
|
||||||
->select(['u', 's', 'us'])
|
->select(['u', 's', 'us'])
|
||||||
->innerJoin('u.subscribers', 's')
|
->innerJoin('u.subscribers', 's')
|
||||||
|
|
|
@ -53,18 +53,40 @@ services:
|
||||||
# Subsribers update
|
# Subsribers update
|
||||||
app.point.update_subscribers_command:
|
app.point.update_subscribers_command:
|
||||||
class: Skobkin\Bundle\PointToolsBundle\Command\UpdateSubscriptionsCommand
|
class: Skobkin\Bundle\PointToolsBundle\Command\UpdateSubscriptionsCommand
|
||||||
#autowire: []
|
arguments:
|
||||||
calls:
|
- '@doctrine.orm.entity_manager'
|
||||||
- [setDeps, ['@logger', '@doctrine.orm.entity_manager', '@app.point.user_repository', '@app.point.api_user', '@app.point.subscriptions_manager']]
|
- '@logger'
|
||||||
- [setApiDelay, ['%point_api_delay%']]
|
- '@app.point.user_repository'
|
||||||
|
- '@app.point.api_user'
|
||||||
|
- '@app.point.subscriptions_manager'
|
||||||
|
- '%point_api_delay%'
|
||||||
|
- '%point_id%'
|
||||||
tags:
|
tags:
|
||||||
- { name: console.command }
|
- { name: console.command }
|
||||||
- { name: monolog.logger, channel: subscribers_update }
|
- { name: monolog.logger, channel: subscribers_update }
|
||||||
|
# Privacy update
|
||||||
|
app.point.update_privacy_command:
|
||||||
|
class: Skobkin\Bundle\PointToolsBundle\Command\UpdateUsersPrivacyCommand
|
||||||
|
#autowire: []
|
||||||
|
arguments:
|
||||||
|
- '@doctrine.orm.entity_manager'
|
||||||
|
- '@logger'
|
||||||
|
- '@app.point.user_repository'
|
||||||
|
- '@app.point.api_user'
|
||||||
|
- '%point_api_delay%'
|
||||||
|
- '%point_id%'
|
||||||
|
tags:
|
||||||
|
- { name: console.command }
|
||||||
|
- { name: monolog.logger, channel: privacy_update }
|
||||||
# Restore users removed by error
|
# Restore users removed by error
|
||||||
app.point.restore_users:
|
app.point.restore_users:
|
||||||
class: Skobkin\Bundle\PointToolsBundle\Command\RestoreRemovedUsersCommand
|
class: Skobkin\Bundle\PointToolsBundle\Command\RestoreRemovedUsersCommand
|
||||||
calls:
|
arguments:
|
||||||
- [setDependencies, ['@logger', '@doctrine.orm.entity_manager', '@app.point.user_repository', '@app.point.api_user', '%point_api_delay%']]
|
- '@logger'
|
||||||
|
- '@doctrine.orm.entity_manager'
|
||||||
|
- '@app.point.user_repository'
|
||||||
|
- '@app.point.api_user'
|
||||||
|
- '%point_api_delay%'
|
||||||
tags:
|
tags:
|
||||||
- { name: console.command }
|
- { name: console.command }
|
||||||
# Webhook management
|
# Webhook management
|
||||||
|
|
|
@ -4,16 +4,10 @@ namespace Skobkin\Bundle\PointToolsBundle\Service\Api;
|
||||||
|
|
||||||
use GuzzleHttp\ClientInterface;
|
use GuzzleHttp\ClientInterface;
|
||||||
use GuzzleHttp\Exception\TransferException;
|
use GuzzleHttp\Exception\TransferException;
|
||||||
use JMS\Serializer\DeserializationContext;
|
use JMS\Serializer\{DeserializationContext, Serializer};
|
||||||
use JMS\Serializer\Serializer;
|
use Psr\Http\Message\{ResponseInterface, StreamInterface};
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
use Psr\Http\Message\StreamInterface;
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\ForbiddenException;
|
use Skobkin\Bundle\PointToolsBundle\Exception\Api\{ForbiddenException, NetworkException, NotFoundException, ServerProblemException, UnauthorizedException};
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\NetworkException;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\NotFoundException;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\ServerProblemException;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\UnauthorizedException;
|
|
||||||
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
|
||||||
|
|
||||||
class AbstractApi
|
class AbstractApi
|
||||||
|
@ -184,7 +178,9 @@ class AbstractApi
|
||||||
// @todo remove after fix
|
// @todo remove after fix
|
||||||
// Temporary fix until @arts fixes this bug
|
// Temporary fix until @arts fixes this bug
|
||||||
if ('{"error": "UserNotFound"}' === (string) $response->getBody()) {
|
if ('{"error": "UserNotFound"}' === (string) $response->getBody()) {
|
||||||
throw new NotFoundException($reason, $code);
|
throw new NotFoundException('Not found', SymfonyResponse::HTTP_NOT_FOUND);
|
||||||
|
} elseif ('{"message": "Forbidden", "code": 403, "error": "Forbidden"}' === (string) $response->getBody()) {
|
||||||
|
throw new ForbiddenException('Forbidden', SymfonyResponse::HTTP_FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($code) {
|
switch ($code) {
|
||||||
|
|
|
@ -3,16 +3,11 @@
|
||||||
namespace Skobkin\Bundle\PointToolsBundle\Service\Api;
|
namespace Skobkin\Bundle\PointToolsBundle\Service\Api;
|
||||||
|
|
||||||
use GuzzleHttp\ClientInterface;
|
use GuzzleHttp\ClientInterface;
|
||||||
use JMS\Serializer\DeserializationContext;
|
use JMS\Serializer\{DeserializationContext, Serializer};
|
||||||
use JMS\Serializer\Serializer;
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Skobkin\Bundle\PointToolsBundle\DTO\Api\Auth;
|
use Skobkin\Bundle\PointToolsBundle\DTO\Api\{Auth, User as UserDTO};
|
||||||
use Skobkin\Bundle\PointToolsBundle\DTO\Api\User as UserDTO;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Entity\User;
|
use Skobkin\Bundle\PointToolsBundle\Entity\User;
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\ForbiddenException;
|
use Skobkin\Bundle\PointToolsBundle\Exception\Api\{ForbiddenException, InvalidResponseException, NotFoundException, UserNotFoundException};
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\InvalidResponseException;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\NotFoundException;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Exception\Api\UserNotFoundException;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Service\Factory\UserFactory;
|
use Skobkin\Bundle\PointToolsBundle\Service\Factory\UserFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -177,6 +172,7 @@ class UserApi extends AbstractApi
|
||||||
} catch (NotFoundException $e) {
|
} catch (NotFoundException $e) {
|
||||||
throw new UserNotFoundException('User not found', 0, $e, $id);
|
throw new UserNotFoundException('User not found', 0, $e, $id);
|
||||||
}
|
}
|
||||||
|
// Not catching ForbiddenException right now
|
||||||
|
|
||||||
return $this->userFactory->findOrCreateFromDTO($userData);
|
return $this->userFactory->findOrCreateFromDTO($userData);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,10 @@ class UserFactory extends AbstractFactory
|
||||||
|
|
||||||
$user->updateLoginAndName($userData->getLogin(), $userData->getName());
|
$user->updateLoginAndName($userData->getLogin(), $userData->getName());
|
||||||
|
|
||||||
|
if (null !== $userData->getDenyAnonymous() && null !== $userData->getPrivate()) {
|
||||||
|
$user->updatePrivacy(!$userData->getDenyAnonymous(), $userData->getPrivate());
|
||||||
|
}
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
namespace Skobkin\Bundle\PointToolsBundle\Service\Telegram;
|
namespace Skobkin\Bundle\PointToolsBundle\Service\Telegram;
|
||||||
|
|
||||||
use unreal4u\TelegramAPI\Telegram\Types\Inline\Query;
|
use unreal4u\TelegramAPI\Telegram\Types\{Inline\Query, Message, Update};
|
||||||
use unreal4u\TelegramAPI\Telegram\Types\Message;
|
|
||||||
use unreal4u\TelegramAPI\Telegram\Types\Update;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatches incoming messages processing to corresponding services
|
* Dispatches incoming messages processing to corresponding services
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
namespace Skobkin\Bundle\PointToolsBundle\Service\Telegram;
|
namespace Skobkin\Bundle\PointToolsBundle\Service\Telegram;
|
||||||
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Entity\Telegram\Account;
|
use Skobkin\Bundle\PointToolsBundle\Entity\{Telegram\Account, User, UserRenameEvent};
|
||||||
use Skobkin\Bundle\PointToolsBundle\Entity\User;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Entity\UserRenameEvent;
|
|
||||||
use Skobkin\Bundle\PointToolsBundle\Repository\Telegram\AccountRepository;
|
use Skobkin\Bundle\PointToolsBundle\Repository\Telegram\AccountRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue