diff options
39 files changed, 1631 insertions, 109 deletions
@@ -17,6 +17,10 @@ Improvements: * Use Gulp and Bower to manage assets * Controller and Middleware refactoring +Bug fixes: + +* Do not send notifications to disabled users + Version 1.0.28 -------------- diff --git a/app/Console/PluginUpgradeCommand.php b/app/Console/PluginUpgradeCommand.php index 6ec5836d..839124b1 100644 --- a/app/Console/PluginUpgradeCommand.php +++ b/app/Console/PluginUpgradeCommand.php @@ -3,6 +3,7 @@ namespace Kanboard\Console; use Kanboard\Core\Plugin\Base as BasePlugin; +use Kanboard\Core\Plugin\Directory; use Kanboard\Core\Plugin\Installer; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -24,7 +25,7 @@ class PluginUpgradeCommand extends BaseCommand } $installer = new Installer($this->container); - $availablePlugins = $this->httpClient->getJson(PLUGIN_API_URL); + $availablePlugins = Directory::getInstance($this->container)->getAvailablePlugins(); foreach ($this->pluginLoader->getPlugins() as $installedPlugin) { $pluginDetails = $this->getPluginDetails($availablePlugins, $installedPlugin); diff --git a/app/Console/WorkerCommand.php b/app/Console/WorkerCommand.php new file mode 100644 index 00000000..e332624b --- /dev/null +++ b/app/Console/WorkerCommand.php @@ -0,0 +1,28 @@ +<?php + +namespace Kanboard\Console; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Class WorkerCommand + * + * @package Kanboard\Console + * @author Frederic Guillot + */ +class WorkerCommand extends BaseCommand +{ + protected function configure() + { + $this + ->setName('worker') + ->setDescription('Execute queue worker') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->queueManager->listen(); + } +} diff --git a/app/Controller/PluginController.php b/app/Controller/PluginController.php index b6f9a33b..7b9d64d9 100644 --- a/app/Controller/PluginController.php +++ b/app/Controller/PluginController.php @@ -2,6 +2,7 @@ namespace Kanboard\Controller; +use Kanboard\Core\Plugin\Directory; use Kanboard\Core\Plugin\Installer; use Kanboard\Core\Plugin\PluginInstallerException; @@ -40,7 +41,7 @@ class PluginController extends BaseController $this->response->html($this->helper->layout->plugin('plugin/directory', array( 'installed_plugins' => $installedPlugins, - 'available_plugins' => $this->httpClient->getJson(PLUGIN_API_URL), + 'available_plugins' => Directory::getInstance($this->container)->getAvailablePlugins(), 'title' => t('Plugin Directory'), 'is_configured' => Installer::isConfigured(), ))); diff --git a/app/Core/Base.php b/app/Core/Base.php index 39a8ccd6..e490484c 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -27,6 +27,7 @@ use Pimple\Container; * @property \Kanboard\Core\Http\Response $response * @property \Kanboard\Core\Http\Router $router * @property \Kanboard\Core\Http\Route $route + * @property \Kanboard\Core\Queue\QueueManager $queueManager * @property \Kanboard\Core\Mail\Client $emailClient * @property \Kanboard\Core\ObjectStorage\ObjectStorageInterface $objectStorage * @property \Kanboard\Core\Plugin\Hook $hook diff --git a/app/Core/Mail/Client.php b/app/Core/Mail/Client.php index 641b6abe..44f4753a 100644 --- a/app/Core/Mail/Client.php +++ b/app/Core/Mail/Client.php @@ -2,6 +2,7 @@ namespace Kanboard\Core\Mail; +use Kanboard\Job\EmailJob; use Pimple\Container; use Kanboard\Core\Base; @@ -46,23 +47,29 @@ class Client extends Base public function send($email, $name, $subject, $html) { if (! empty($email)) { - $this->logger->debug('Sending email to '.$email.' ('.MAIL_TRANSPORT.')'); - - $start_time = microtime(true); - $author = 'Kanboard'; + $this->queueManager->push(EmailJob::getInstance($this->container) + ->withParams($email, $name, $subject, $html, $this->getAuthor()) + ); + } - if ($this->userSession->isLogged()) { - $author = e('%s via Kanboard', $this->helper->user->getFullname()); - } + return $this; + } - $this->getTransport(MAIL_TRANSPORT)->sendEmail($email, $name, $subject, $html, $author); + /** + * Get email author + * + * @access public + * @return string + */ + public function getAuthor() + { + $author = 'Kanboard'; - if (DEBUG) { - $this->logger->debug('Email sent in '.round(microtime(true) - $start_time, 6).' seconds'); - } + if ($this->userSession->isLogged()) { + $author = e('%s via Kanboard', $this->helper->user->getFullname()); } - return $this; + return $author; } /** diff --git a/app/Core/Plugin/Directory.php b/app/Core/Plugin/Directory.php new file mode 100644 index 00000000..21f11ca9 --- /dev/null +++ b/app/Core/Plugin/Directory.php @@ -0,0 +1,56 @@ +<?php + +namespace Kanboard\Core\Plugin; + +use Kanboard\Core\Base as BaseCore; + +/** + * Class Directory + * + * @package Kanboard\Core\Plugin + * @author Frederic Guillot + */ +class Directory extends BaseCore +{ + /** + * Get all plugins available + * + * @access public + * @param string $url + * @return array + */ + public function getAvailablePlugins($url = PLUGIN_API_URL) + { + $plugins = $this->httpClient->getJson($url); + $plugins = array_filter($plugins, array($this, 'isCompatible')); + $plugins = array_filter($plugins, array($this, 'isInstallable')); + return $plugins; + } + + /** + * Filter plugins + * + * @param array $plugin + * @param string $appVersion + * @return bool + */ + public function isCompatible(array $plugin, $appVersion = APP_VERSION) + { + if (strpos($appVersion, 'master') !== false) { + return true; + } + + return $plugin['compatible_version'] === $appVersion; + } + + /** + * Filter plugins + * + * @param array $plugin + * @return bool + */ + public function isInstallable(array $plugin) + { + return $plugin['remote_install']; + } +} diff --git a/app/Core/Queue/JobHandler.php b/app/Core/Queue/JobHandler.php new file mode 100644 index 00000000..a2c4a2c7 --- /dev/null +++ b/app/Core/Queue/JobHandler.php @@ -0,0 +1,50 @@ +<?php + +namespace Kanboard\Core\Queue; + +use Kanboard\Core\Base; +use Kanboard\Job\BaseJob; +use SimpleQueue\Job; + +/** + * Class JobHandler + * + * @package Kanboard\Core\Queue + * @author Frederic Guillot + */ +class JobHandler extends Base +{ + /** + * Serialize a job + * + * @access public + * @param BaseJob $job + * @return Job + */ + public function serializeJob(BaseJob $job) + { + return new Job(array( + 'class' => get_class($job), + 'params' => $job->getJobParams(), + )); + } + + /** + * Execute a job + * + * @access public + * @param Job $job + */ + public function executeJob(Job $job) + { + $payload = $job->getBody(); + $className = $payload['class']; + + if (DEBUG) { + $this->logger->debug(__METHOD__.' Received job => '.$className); + } + + $worker = new $className($this->container); + call_user_func_array(array($worker, 'execute'), $payload['params']); + } +} diff --git a/app/Core/Queue/QueueManager.php b/app/Core/Queue/QueueManager.php new file mode 100644 index 00000000..f34cb220 --- /dev/null +++ b/app/Core/Queue/QueueManager.php @@ -0,0 +1,71 @@ +<?php + +namespace Kanboard\Core\Queue; + +use Kanboard\Core\Base; +use Kanboard\Job\BaseJob; +use LogicException; +use SimpleQueue\Queue; + +/** + * Class QueueManager + * + * @package Kanboard\Core\Queue + * @author Frederic Guillot + */ +class QueueManager extends Base +{ + /** + * @var Queue + */ + protected $queue = null; + + /** + * Set queue driver + * + * @access public + * @param Queue $queue + * @return $this + */ + public function setQueue(Queue $queue) + { + $this->queue = $queue; + return $this; + } + + /** + * Send a new job to the queue + * + * @access public + * @param BaseJob $job + * @return $this + */ + public function push(BaseJob $job) + { + if ($this->queue !== null) { + $this->queue->push(JobHandler::getInstance($this->container)->serializeJob($job)); + } else { + call_user_func_array(array($job, 'execute'), $job->getJobParams()); + } + + return $this; + } + + /** + * Wait for new jobs + * + * @access public + * @throws LogicException + */ + public function listen() + { + if ($this->queue === null) { + throw new LogicException('No Queue Driver defined!'); + } + + while ($job = $this->queue->pull()) { + JobHandler::getInstance($this->container)->executeJob($job); + $this->queue->completed($job); + } + } +} diff --git a/app/Job/BaseJob.php b/app/Job/BaseJob.php new file mode 100644 index 00000000..60522ac6 --- /dev/null +++ b/app/Job/BaseJob.php @@ -0,0 +1,33 @@ +<?php + +namespace Kanboard\Job; + +use Kanboard\Core\Base; + +/** + * Class BaseJob + * + * @package Kanboard\Job + * @author Frederic Guillot + */ +abstract class BaseJob extends Base +{ + /** + * Job parameters + * + * @access protected + * @var array + */ + protected $jobParams = array(); + + /** + * Get job parameters + * + * @access public + * @return array + */ + public function getJobParams() + { + return $this->jobParams; + } +} diff --git a/app/Job/EmailJob.php b/app/Job/EmailJob.php new file mode 100644 index 00000000..9293a1d4 --- /dev/null +++ b/app/Job/EmailJob.php @@ -0,0 +1,54 @@ +<?php + +namespace Kanboard\Job; + +/** + * Class EmailJob + * + * @package Kanboard\Job + * @author Frederic Guillot + */ +class EmailJob extends BaseJob +{ + /** + * Set job parameters + * + * @access public + * @param string $email + * @param string $name + * @param string $subject + * @param string $html + * @param string $author + * @return $this + */ + public function withParams($email, $name, $subject, $html, $author) + { + $this->jobParams = array($email, $name, $subject, $html, $author); + return $this; + } + + /** + * Execute job + * + * @access public + * @param string $email + * @param string $name + * @param string $subject + * @param string $html + * @param string $author + */ + public function execute($email, $name, $subject, $html, $author) + { + $this->logger->debug(__METHOD__.' Sending email to '.$email.' via '.MAIL_TRANSPORT); + $startTime = microtime(true); + + $this->emailClient + ->getTransport(MAIL_TRANSPORT) + ->sendEmail($email, $name, $subject, $html, $author) + ; + + if (DEBUG) { + $this->logger->debug('Email sent in '.round(microtime(true) - $startTime, 6).' seconds'); + } + } +} diff --git a/app/Job/NotificationJob.php b/app/Job/NotificationJob.php new file mode 100644 index 00000000..d5fce222 --- /dev/null +++ b/app/Job/NotificationJob.php @@ -0,0 +1,85 @@ +<?php + +namespace Kanboard\Job; + +use Kanboard\Event\GenericEvent; + +/** + * Class NotificationJob + * + * @package Kanboard\Job + * @author Frederic Guillot + */ +class NotificationJob extends BaseJob +{ + /** + * Set job parameters + * + * @param GenericEvent $event + * @param string $eventName + * @param string $eventObjectName + * @return $this + */ + public function withParams(GenericEvent $event, $eventName, $eventObjectName) + { + $this->jobParams = array($event->getAll(), $eventName, $eventObjectName); + return $this; + } + + /** + * Execute job + * + * @param array $event + * @param string $eventName + * @param string $eventObjectName + */ + public function execute(array $event, $eventName, $eventObjectName) + { + $eventData = $this->getEventData($event, $eventObjectName); + + if (! empty($eventData)) { + if (! empty($event['mention'])) { + $this->userNotification->sendUserNotification($event['mention'], $eventName, $eventData); + } else { + $this->userNotification->sendNotifications($eventName, $eventData); + $this->projectNotification->sendNotifications($eventData['task']['project_id'], $eventName, $eventData); + } + } + } + + /** + * Get event data + * + * @param array $event + * @param string $eventObjectName + * @return array + */ + public function getEventData(array $event, $eventObjectName) + { + $values = array(); + + if (! empty($event['changes'])) { + $values['changes'] = $event['changes']; + } + + switch ($eventObjectName) { + case 'Kanboard\Event\TaskEvent': + $values['task'] = $this->taskFinder->getDetails($event['task_id']); + break; + case 'Kanboard\Event\SubtaskEvent': + $values['subtask'] = $this->subtask->getById($event['id'], true); + $values['task'] = $this->taskFinder->getDetails($values['subtask']['task_id']); + break; + case 'Kanboard\Event\FileEvent': + $values['file'] = $event; + $values['task'] = $this->taskFinder->getDetails($values['file']['task_id']); + break; + case 'Kanboard\Event\CommentEvent': + $values['comment'] = $this->comment->getById($event['id']); + $values['task'] = $this->taskFinder->getDetails($values['comment']['task_id']); + break; + } + + return $values; + } +} diff --git a/app/Job/ProjectMetricJob.php b/app/Job/ProjectMetricJob.php new file mode 100644 index 00000000..2c3e589c --- /dev/null +++ b/app/Job/ProjectMetricJob.php @@ -0,0 +1,40 @@ +<?php + +namespace Kanboard\Job; + +/** + * Class ProjectMetricJob + * + * @package Kanboard\Job + * @author Frederic Guillot + */ +class ProjectMetricJob extends BaseJob +{ + /** + * Set job parameters + * + * @access public + * @param integer $projectId + * @return $this + */ + public function withParams($projectId) + { + $this->jobParams = array($projectId); + return $this; + } + + /** + * Execute job + * + * @access public + * @param integer $projectId + */ + public function execute($projectId) + { + $this->logger->debug(__METHOD__.' Run project metrics calculation'); + $now = date('Y-m-d'); + + $this->projectDailyColumnStats->updateTotals($projectId, $now); + $this->projectDailyStats->updateTotals($projectId, $now); + } +} diff --git a/app/Model/UserNotification.php b/app/Model/UserNotification.php index fcd1761b..6882e671 100644 --- a/app/Model/UserNotification.php +++ b/app/Model/UserNotification.php @@ -162,8 +162,9 @@ class UserNotification extends Base ->table(ProjectUserRole::TABLE) ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language', User::TABLE.'.notifications_filter') ->join(User::TABLE, 'id', 'user_id') - ->eq('project_id', $project_id) - ->eq('notifications_enabled', '1') + ->eq(ProjectUserRole::TABLE.'.project_id', $project_id) + ->eq(User::TABLE.'.notifications_enabled', '1') + ->eq(User::TABLE.'.is_active', 1) ->neq(User::TABLE.'.id', $exclude_user_id) ->findAll(); } @@ -178,6 +179,7 @@ class UserNotification extends Base ->eq(ProjectGroupRole::TABLE.'.project_id', $project_id) ->eq(User::TABLE.'.notifications_enabled', '1') ->neq(User::TABLE.'.id', $exclude_user_id) + ->eq(User::TABLE.'.is_active', 1) ->findAll(); } @@ -195,6 +197,7 @@ class UserNotification extends Base ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language', User::TABLE.'.notifications_filter') ->eq('notifications_enabled', '1') ->neq(User::TABLE.'.id', $exclude_user_id) + ->eq(User::TABLE.'.is_active', 1) ->findAll(); } } diff --git a/app/ServiceProvider/ActionProvider.php b/app/ServiceProvider/ActionProvider.php index 7c92f3ce..34202052 100644 --- a/app/ServiceProvider/ActionProvider.php +++ b/app/ServiceProvider/ActionProvider.php @@ -36,7 +36,7 @@ use Kanboard\Action\TaskCloseNoActivity; /** * Action Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class ActionProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/AuthenticationProvider.php b/app/ServiceProvider/AuthenticationProvider.php index 6b037940..d4f130e2 100644 --- a/app/ServiceProvider/AuthenticationProvider.php +++ b/app/ServiceProvider/AuthenticationProvider.php @@ -17,7 +17,7 @@ use Kanboard\Auth\ReverseProxyAuth; /** * Authentication Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class AuthenticationProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/AvatarProvider.php b/app/ServiceProvider/AvatarProvider.php index aac4fcab..d17985ed 100644 --- a/app/ServiceProvider/AvatarProvider.php +++ b/app/ServiceProvider/AvatarProvider.php @@ -12,7 +12,7 @@ use Kanboard\User\Avatar\LetterAvatarProvider; /** * Avatar Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class AvatarProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index 31e3a20b..154b921f 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -11,6 +11,12 @@ use Kanboard\Core\Http\OAuth2; use Kanboard\Core\Tool; use Kanboard\Core\Http\Client as HttpClient; +/** + * Class ClassProvider + * + * @package Kanboard\ServiceProvider + * @author Frederic Guillot + */ class ClassProvider implements ServiceProviderInterface { private $classes = array( diff --git a/app/ServiceProvider/DatabaseProvider.php b/app/ServiceProvider/DatabaseProvider.php index c0dcd366..a3f57457 100644 --- a/app/ServiceProvider/DatabaseProvider.php +++ b/app/ServiceProvider/DatabaseProvider.php @@ -8,6 +8,12 @@ use Pimple\Container; use Pimple\ServiceProviderInterface; use PicoDb\Database; +/** + * Class DatabaseProvider + * + * @package Kanboard\ServiceProvider + * @author Frederic Guillot + */ class DatabaseProvider implements ServiceProviderInterface { /** diff --git a/app/ServiceProvider/EventDispatcherProvider.php b/app/ServiceProvider/EventDispatcherProvider.php index 6b3dc098..57543fe4 100644 --- a/app/ServiceProvider/EventDispatcherProvider.php +++ b/app/ServiceProvider/EventDispatcherProvider.php @@ -15,6 +15,12 @@ use Kanboard\Subscriber\SubtaskTimeTrackingSubscriber; use Kanboard\Subscriber\TransitionSubscriber; use Kanboard\Subscriber\RecurringTaskSubscriber; +/** + * Class EventDispatcherProvider + * + * @package Kanboard\ServiceProvider + * @author Frederic Guillot + */ class EventDispatcherProvider implements ServiceProviderInterface { public function register(Container $container) diff --git a/app/ServiceProvider/ExternalLinkProvider.php b/app/ServiceProvider/ExternalLinkProvider.php index 8b71ec81..2cec768d 100644 --- a/app/ServiceProvider/ExternalLinkProvider.php +++ b/app/ServiceProvider/ExternalLinkProvider.php @@ -12,7 +12,7 @@ use Kanboard\ExternalLink\FileLinkProvider; /** * External Link Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class ExternalLinkProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/FilterProvider.php b/app/ServiceProvider/FilterProvider.php index f3918d77..b79c5185 100644 --- a/app/ServiceProvider/FilterProvider.php +++ b/app/ServiceProvider/FilterProvider.php @@ -37,7 +37,7 @@ use Pimple\ServiceProviderInterface; /** * Filter Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class FilterProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/GroupProvider.php b/app/ServiceProvider/GroupProvider.php index b222b218..08548c73 100644 --- a/app/ServiceProvider/GroupProvider.php +++ b/app/ServiceProvider/GroupProvider.php @@ -11,7 +11,7 @@ use Kanboard\Group\LdapBackendGroupProvider; /** * Group Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class GroupProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/HelperProvider.php b/app/ServiceProvider/HelperProvider.php index bf3956a2..114212d2 100644 --- a/app/ServiceProvider/HelperProvider.php +++ b/app/ServiceProvider/HelperProvider.php @@ -7,6 +7,12 @@ use Kanboard\Core\Template; use Pimple\Container; use Pimple\ServiceProviderInterface; +/** + * Class HelperProvider + * + * @package Kanboard\ServiceProvider + * @author Frederic Guillot + */ class HelperProvider implements ServiceProviderInterface { public function register(Container $container) diff --git a/app/ServiceProvider/LoggingProvider.php b/app/ServiceProvider/LoggingProvider.php index 4d6adbe4..cb6d0baa 100644 --- a/app/ServiceProvider/LoggingProvider.php +++ b/app/ServiceProvider/LoggingProvider.php @@ -11,6 +11,12 @@ use SimpleLogger\Stdout; use SimpleLogger\Syslog; use SimpleLogger\File; +/** + * Class LoggingProvider + * + * @package Kanboard\ServiceProvider + * @author Frederic Guillot + */ class LoggingProvider implements ServiceProviderInterface { public function register(Container $container) diff --git a/app/ServiceProvider/NotificationProvider.php b/app/ServiceProvider/NotificationProvider.php index 83daf65d..23d1d516 100644 --- a/app/ServiceProvider/NotificationProvider.php +++ b/app/ServiceProvider/NotificationProvider.php @@ -12,7 +12,7 @@ use Kanboard\Notification\Web as WebNotification; /** * Notification Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class NotificationProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/PluginProvider.php b/app/ServiceProvider/PluginProvider.php index d2f1666b..4cf57251 100644 --- a/app/ServiceProvider/PluginProvider.php +++ b/app/ServiceProvider/PluginProvider.php @@ -9,7 +9,7 @@ use Kanboard\Core\Plugin\Loader; /** * Plugin Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class PluginProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/QueueProvider.php b/app/ServiceProvider/QueueProvider.php new file mode 100644 index 00000000..946b436a --- /dev/null +++ b/app/ServiceProvider/QueueProvider.php @@ -0,0 +1,27 @@ +<?php + +namespace Kanboard\ServiceProvider; + +use Kanboard\Core\Queue\QueueManager; +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class QueueProvider + * + * @package Kanboard\ServiceProvider + * @author Frederic Guillot + */ +class QueueProvider implements ServiceProviderInterface +{ + /** + * Registers services on the given container. + * + * @param Container $container + */ + public function register(Container $container) + { + $container['queueManager'] = new QueueManager($container); + return $container; + } +} diff --git a/app/ServiceProvider/RouteProvider.php b/app/ServiceProvider/RouteProvider.php index a7338994..4a126b58 100644 --- a/app/ServiceProvider/RouteProvider.php +++ b/app/ServiceProvider/RouteProvider.php @@ -10,7 +10,7 @@ use Kanboard\Core\Http\Router; /** * Route Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class RouteProvider implements ServiceProviderInterface diff --git a/app/ServiceProvider/SessionProvider.php b/app/ServiceProvider/SessionProvider.php index 0999d531..96dcac2e 100644 --- a/app/ServiceProvider/SessionProvider.php +++ b/app/ServiceProvider/SessionProvider.php @@ -11,7 +11,7 @@ use Kanboard\Core\Session\FlashMessage; /** * Session Provider * - * @package serviceProvider + * @package Kanboard\ServiceProvider * @author Frederic Guillot */ class SessionProvider implements ServiceProviderInterface diff --git a/app/Subscriber/NotificationSubscriber.php b/app/Subscriber/NotificationSubscriber.php index 651b8a96..2a1fe6c7 100644 --- a/app/Subscriber/NotificationSubscriber.php +++ b/app/Subscriber/NotificationSubscriber.php @@ -3,6 +3,7 @@ namespace Kanboard\Subscriber; use Kanboard\Event\GenericEvent; +use Kanboard\Job\NotificationJob; use Kanboard\Model\Task; use Kanboard\Model\Comment; use Kanboard\Model\Subtask; @@ -14,67 +15,32 @@ class NotificationSubscriber extends BaseSubscriber implements EventSubscriberIn public static function getSubscribedEvents() { return array( - Task::EVENT_USER_MENTION => 'handleEvent', - Task::EVENT_CREATE => 'handleEvent', - Task::EVENT_UPDATE => 'handleEvent', - Task::EVENT_CLOSE => 'handleEvent', - Task::EVENT_OPEN => 'handleEvent', - Task::EVENT_MOVE_COLUMN => 'handleEvent', - Task::EVENT_MOVE_POSITION => 'handleEvent', - Task::EVENT_MOVE_SWIMLANE => 'handleEvent', + Task::EVENT_USER_MENTION => 'handleEvent', + Task::EVENT_CREATE => 'handleEvent', + Task::EVENT_UPDATE => 'handleEvent', + Task::EVENT_CLOSE => 'handleEvent', + Task::EVENT_OPEN => 'handleEvent', + Task::EVENT_MOVE_COLUMN => 'handleEvent', + Task::EVENT_MOVE_POSITION => 'handleEvent', + Task::EVENT_MOVE_SWIMLANE => 'handleEvent', Task::EVENT_ASSIGNEE_CHANGE => 'handleEvent', - Subtask::EVENT_CREATE => 'handleEvent', - Subtask::EVENT_UPDATE => 'handleEvent', - Comment::EVENT_CREATE => 'handleEvent', - Comment::EVENT_UPDATE => 'handleEvent', + Subtask::EVENT_CREATE => 'handleEvent', + Subtask::EVENT_UPDATE => 'handleEvent', + Comment::EVENT_CREATE => 'handleEvent', + Comment::EVENT_UPDATE => 'handleEvent', Comment::EVENT_USER_MENTION => 'handleEvent', - TaskFile::EVENT_CREATE => 'handleEvent', + TaskFile::EVENT_CREATE => 'handleEvent', ); } - public function handleEvent(GenericEvent $event, $event_name) + public function handleEvent(GenericEvent $event, $eventName) { - if (! $this->isExecuted($event_name)) { - $this->logger->debug('Subscriber executed: '.__METHOD__); - $event_data = $this->getEventData($event); + if (!$this->isExecuted($eventName)) { + $this->logger->debug('Subscriber executed: ' . __METHOD__); - if (! empty($event_data)) { - if (! empty($event['mention'])) { - $this->userNotification->sendUserNotification($event['mention'], $event_name, $event_data); - } else { - $this->userNotification->sendNotifications($event_name, $event_data); - $this->projectNotification->sendNotifications($event_data['task']['project_id'], $event_name, $event_data); - } - } + $this->queueManager->push(NotificationJob::getInstance($this->container) + ->withParams($event, $eventName, get_class($event)) + ); } } - - public function getEventData(GenericEvent $event) - { - $values = array(); - - if (! empty($event['changes'])) { - $values['changes'] = $event['changes']; - } - - switch (get_class($event)) { - case 'Kanboard\Event\TaskEvent': - $values['task'] = $this->taskFinder->getDetails($event['task_id']); - break; - case 'Kanboard\Event\SubtaskEvent': - $values['subtask'] = $this->subtask->getById($event['id'], true); - $values['task'] = $this->taskFinder->getDetails($values['subtask']['task_id']); - break; - case 'Kanboard\Event\FileEvent': - $values['file'] = $event->getAll(); - $values['task'] = $this->taskFinder->getDetails($values['file']['task_id']); - break; - case 'Kanboard\Event\CommentEvent': - $values['comment'] = $this->comment->getById($event['id']); - $values['task'] = $this->taskFinder->getDetails($values['comment']['task_id']); - break; - } - - return $values; - } } diff --git a/app/Subscriber/ProjectDailySummarySubscriber.php b/app/Subscriber/ProjectDailySummarySubscriber.php index 44138f43..982240c1 100644 --- a/app/Subscriber/ProjectDailySummarySubscriber.php +++ b/app/Subscriber/ProjectDailySummarySubscriber.php @@ -3,6 +3,7 @@ namespace Kanboard\Subscriber; use Kanboard\Event\TaskEvent; +use Kanboard\Job\ProjectMetricJob; use Kanboard\Model\Task; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -23,8 +24,7 @@ class ProjectDailySummarySubscriber extends BaseSubscriber implements EventSubsc { if (isset($event['project_id']) && !$this->isExecuted()) { $this->logger->debug('Subscriber executed: '.__METHOD__); - $this->projectDailyColumnStats->updateTotals($event['project_id'], date('Y-m-d')); - $this->projectDailyStats->updateTotals($event['project_id'], date('Y-m-d')); + $this->queueManager->push(ProjectMetricJob::getInstance($this->container)->withParams($event['project_id'])); } } } diff --git a/app/common.php b/app/common.php index fa95773b..e018aa12 100644 --- a/app/common.php +++ b/app/common.php @@ -45,4 +45,5 @@ $container->register(new Kanboard\ServiceProvider\ActionProvider()); $container->register(new Kanboard\ServiceProvider\ExternalLinkProvider()); $container->register(new Kanboard\ServiceProvider\AvatarProvider()); $container->register(new Kanboard\ServiceProvider\FilterProvider()); +$container->register(new Kanboard\ServiceProvider\QueueProvider()); $container->register(new Kanboard\ServiceProvider\PluginProvider()); diff --git a/composer.json b/composer.json index df91d0c5..5cdac14a 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ "fguillot/picodb" : "1.0.11", "fguillot/simpleLogger" : "1.0.1", "fguillot/simple-validator" : "1.0.0", + "fguillot/simple-queue" : "dev-master", "paragonie/random_compat": "@stable", "pimple/pimple" : "~3.0", "ramsey/array_column": "@stable", @@ -49,6 +50,7 @@ ] }, "require-dev" : { - "symfony/stopwatch" : "~2.6" + "symfony/stopwatch" : "~2.6", + "phpunit/phpunit": "4.8.*" } } diff --git a/composer.lock b/composer.lock index 91d88ee2..fa5b52f3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "7679ea6537bad9f8be67619d321a72f9", - "content-hash": "ef2d3ad0af1dcad85710d537150ec151", + "hash": "7dce69b83d7c6e14d2260e7b63352f8c", + "content-hash": "39143d0a5ad67dd0394826aa1845cad7", "packages": [ { "name": "christian-riesen/base32", @@ -275,6 +275,55 @@ "time": "2016-05-15 01:02:48" }, { + "name": "fguillot/simple-queue", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/fguillot/simple-queue.git", + "reference": "ae4359e9ee3b36da646766557c9242bb6ee3dcab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fguillot/simple-queue/zipball/ae4359e9ee3b36da646766557c9242bb6ee3dcab", + "reference": "ae4359e9ee3b36da646766557c9242bb6ee3dcab", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "aws/aws-sdk-php": "~3.0", + "mariano/disque-php": "~2.0", + "pda/pheanstalk": "~3.0", + "php-amqplib/php-amqplib": "2.6.*", + "phpunit/phpunit": "5.3.*" + }, + "suggest": { + "aws/aws-sdk-php": "Required to use the AWS SQS queue driver (~3.0).", + "mariano/disque-php": "Required to use the Disque queue driver (~2.0).", + "pda/pheanstalk": "Required to use the Beanstalk queue driver (~3.0).", + "php-amqplib/php-amqplib": "Required to use the RabbitMQ queue driver (2.6.*)." + }, + "type": "library", + "autoload": { + "psr-4": { + "SimpleQueue\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frédéric Guillot" + } + ], + "description": "Abstraction layer for multiple queue systems", + "homepage": "https://github.com/fguillot/simple-queue", + "time": "2016-05-24 23:58:05" + }, + { "name": "fguillot/simple-validator", "version": "1.0.0", "source": { @@ -747,16 +796,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.1.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "1289d16209491b584839022f29257ad859b8532d" + "reference": "dff51f72b0706335131b00a7f49606168c582594" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d", - "reference": "1289d16209491b584839022f29257ad859b8532d", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", + "reference": "dff51f72b0706335131b00a7f49606168c582594", "shasum": "" }, "require": { @@ -768,7 +817,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -802,11 +851,918 @@ "portable", "shim" ], - "time": "2016-01-20 09:13:37" + "time": "2016-05-18 14:26:46" } ], "packages-dev": [ { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972", + "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "~2.0", + "sebastian/comparator": "~1.1", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-02-15 07:46:21" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06 15:47:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21 13:08:43" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12 18:03:57" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15 10:49:45" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.26", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74", + "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2016-05-17 03:09:28" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02 06:51:40" + }, + { + "name": "sebastian/comparator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-07-26 15:48:44" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08 07:14:41" + }, + { + "name": "sebastian/environment", + "version": "1.3.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-05-17 03:18:57" + }, + { + "name": "sebastian/exporter", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "7ae5513327cb536431847bcc0c10edba2701064e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", + "reference": "7ae5513327cb536431847bcc0c10edba2701064e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-06-21 07:55:53" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12 03:26:01" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-11-11 19:50:13" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21 13:59:46" + }, + { "name": "symfony/stopwatch", "version": "v2.8.6", "source": { @@ -854,11 +1810,61 @@ "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", "time": "2016-03-04 07:54:35" + }, + { + "name": "symfony/yaml", + "version": "v3.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "0047c8366744a16de7516622c5b7355336afae96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96", + "reference": "0047c8366744a16de7516622c5b7355336afae96", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2016-03-04 07:55:57" } ], "aliases": [], "minimum-stability": "stable", "stability-flags": { + "fguillot/simple-queue": 20, "paragonie/random_compat": 0, "ramsey/array_column": 0 }, @@ -6,6 +6,7 @@ use Kanboard\Console\PluginUninstallCommand; use Kanboard\Console\PluginUpgradeCommand; use Kanboard\Console\ResetPasswordCommand; use Kanboard\Console\ResetTwoFactorCommand; +use Kanboard\Console\WorkerCommand; use Symfony\Component\Console\Application; use Symfony\Component\EventDispatcher\Event; use Kanboard\Console\TaskOverdueNotificationCommand; @@ -37,6 +38,7 @@ try { $application->add(new LocaleComparatorCommand($container)); $application->add(new TaskTriggerCommand($container)); $application->add(new CronjobCommand($container)); + $application->add(new WorkerCommand($container)); $application->add(new ResetPasswordCommand($container)); $application->add(new ResetTwoFactorCommand($container)); $application->add(new PluginUpgradeCommand($container)); diff --git a/tests/units/Base.php b/tests/units/Base.php index 171f9b2b..16c34573 100644 --- a/tests/units/Base.php +++ b/tests/units/Base.php @@ -33,14 +33,15 @@ abstract class Base extends PHPUnit_Framework_TestCase } $this->container = new Pimple\Container; - $this->container->register(new Kanboard\ServiceProvider\HelperProvider); - $this->container->register(new Kanboard\ServiceProvider\AuthenticationProvider); - $this->container->register(new Kanboard\ServiceProvider\DatabaseProvider); - $this->container->register(new Kanboard\ServiceProvider\ClassProvider); - $this->container->register(new Kanboard\ServiceProvider\NotificationProvider); - $this->container->register(new Kanboard\ServiceProvider\RouteProvider); - $this->container->register(new Kanboard\ServiceProvider\AvatarProvider); - $this->container->register(new Kanboard\ServiceProvider\FilterProvider); + $this->container->register(new Kanboard\ServiceProvider\HelperProvider()); + $this->container->register(new Kanboard\ServiceProvider\AuthenticationProvider()); + $this->container->register(new Kanboard\ServiceProvider\DatabaseProvider()); + $this->container->register(new Kanboard\ServiceProvider\ClassProvider()); + $this->container->register(new Kanboard\ServiceProvider\NotificationProvider()); + $this->container->register(new Kanboard\ServiceProvider\RouteProvider()); + $this->container->register(new Kanboard\ServiceProvider\AvatarProvider()); + $this->container->register(new Kanboard\ServiceProvider\FilterProvider()); + $this->container->register(new Kanboard\ServiceProvider\QueueProvider()); $this->container['dispatcher'] = new TraceableEventDispatcher( new EventDispatcher, diff --git a/tests/units/Core/Plugin/DirectoryTest.php b/tests/units/Core/Plugin/DirectoryTest.php new file mode 100644 index 00000000..13aef4b9 --- /dev/null +++ b/tests/units/Core/Plugin/DirectoryTest.php @@ -0,0 +1,44 @@ +<?php + +use Kanboard\Core\Plugin\Directory; + +require_once __DIR__.'/../../Base.php'; + +class DirectoryTest extends Base +{ + public function testIsCompatible() + { + $pluginDirectory = new Directory($this->container); + $this->assertFalse($pluginDirectory->isCompatible(array('compatible_version' => '1.0.29'), '1.0.28')); + $this->assertTrue($pluginDirectory->isCompatible(array('compatible_version' => '1.0.28'), '1.0.28')); + $this->assertTrue($pluginDirectory->isCompatible(array('compatible_version' => '1.0.28'), 'master.1234')); + } + + public function testGetAvailablePlugins() + { + $plugins = array( + array( + 'title' => 'Plugin A', + 'compatible_version' => '1.0.30', + 'remote_install' => true, + ), + array( + 'title' => 'Plugin B', + 'compatible_version' => '1.0.29', + 'remote_install' => false, + ), + ); + + $this->container['httpClient'] + ->expects($this->once()) + ->method('getJson') + ->with('api_url') + ->will($this->returnValue($plugins)); + + $pluginDirectory = new Directory($this->container); + $availablePlugins = $pluginDirectory->getAvailablePlugins('api_url'); + + $this->assertCount(1, $availablePlugins); + $this->assertEquals('Plugin A', $availablePlugins[0]['title']); + } +} diff --git a/tests/units/Model/UserNotificationTest.php b/tests/units/Model/UserNotificationTest.php index 53034e20..42db54b4 100644 --- a/tests/units/Model/UserNotificationTest.php +++ b/tests/units/Model/UserNotificationTest.php @@ -109,7 +109,8 @@ class UserNotificationTest extends Base $this->assertEquals(2, $userModel->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); $this->assertEquals(3, $userModel->create(array('username' => 'user2', 'email' => '', 'notifications_enabled' => 1))); - $this->assertEquals(4, $userModel->create(array('username' => 'user3'))); + $this->assertEquals(4, $userModel->create(array('username' => 'user3', 'email' => '', 'notifications_enabled' => 1, 'is_active' => 0))); + $this->assertEquals(5, $userModel->create(array('username' => 'user4'))); $this->assertEquals(1, $groupModel->create('G1')); $this->assertEquals(2, $groupModel->create('G2')); @@ -117,6 +118,7 @@ class UserNotificationTest extends Base $this->assertTrue($groupMemberModel->addUser(1, 2)); $this->assertTrue($groupMemberModel->addUser(1, 3)); $this->assertTrue($groupMemberModel->addUser(1, 4)); + $this->assertTrue($groupMemberModel->addUser(1, 5)); $this->assertTrue($groupMemberModel->addUser(2, 2)); $this->assertTrue($groupMemberModel->addUser(2, 3)); @@ -143,26 +145,30 @@ class UserNotificationTest extends Base $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); // Email + Notifications enabled - $this->assertNotFalse($u->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); + $this->assertEquals(2, $u->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); // No email + Notifications enabled - $this->assertNotFalse($u->create(array('username' => 'user2', 'email' => '', 'notifications_enabled' => 1))); + $this->assertEquals(3, $u->create(array('username' => 'user2', 'email' => '', 'notifications_enabled' => 1))); // Email + Notifications enabled - $this->assertNotFalse($u->create(array('username' => 'user3', 'email' => 'user3@here', 'notifications_enabled' => 1))); + $this->assertEquals(4, $u->create(array('username' => 'user3', 'email' => 'user3@here', 'notifications_enabled' => 1))); + + // User disabled + $this->assertEquals(5, $u->create(array('username' => 'user4', 'email' => 'user3@here', 'notifications_enabled' => 1, 'is_active' => 0))); // No email + notifications disabled - $this->assertNotFalse($u->create(array('username' => 'user4'))); + $this->assertEquals(6, $u->create(array('username' => 'user5'))); // Nobody is member of any projects $this->assertEmpty($pp->getUsers(1)); $this->assertEmpty($n->getUsersWithNotificationEnabled(1)); // We allow all users to be member of our projects - $this->assertTrue($pp->addUser(1, 1, Role::PROJECT_MEMBER)); $this->assertTrue($pp->addUser(1, 2, Role::PROJECT_MEMBER)); $this->assertTrue($pp->addUser(1, 3, Role::PROJECT_MEMBER)); $this->assertTrue($pp->addUser(1, 4, Role::PROJECT_MEMBER)); + $this->assertTrue($pp->addUser(1, 5, Role::PROJECT_MEMBER)); + $this->assertTrue($pp->addUser(1, 6, Role::PROJECT_MEMBER)); $this->assertNotEmpty($pp->getUsers(1)); $users = $n->getUsersWithNotificationEnabled(1); @@ -185,16 +191,19 @@ class UserNotificationTest extends Base $this->assertTrue($pp->isEverybodyAllowed(1)); // Email + Notifications enabled - $this->assertNotFalse($u->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); + $this->assertEquals(2, $u->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); // No email + Notifications enabled - $this->assertNotFalse($u->create(array('username' => 'user2', 'email' => '', 'notifications_enabled' => 1))); + $this->assertEquals(3, $u->create(array('username' => 'user2', 'email' => '', 'notifications_enabled' => 1))); // Email + Notifications enabled - $this->assertNotFalse($u->create(array('username' => 'user3', 'email' => 'user3@here', 'notifications_enabled' => 1))); + $this->assertEquals(4, $u->create(array('username' => 'user3', 'email' => 'user3@here', 'notifications_enabled' => 1))); + + // User disabled + $this->assertEquals(5, $u->create(array('username' => 'user4', 'email' => 'user3@here', 'notifications_enabled' => 1, 'is_active' => 0))); // No email + notifications disabled - $this->assertNotFalse($u->create(array('username' => 'user4'))); + $this->assertEquals(6, $u->create(array('username' => 'user5'))); $users = $n->getUsersWithNotificationEnabled(1); |