From b2e92480c29acb15586bc8ea305c8416927a667c Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Fri, 24 Jun 2016 11:40:58 -0400 Subject: Added filter class for tags --- tests/units/Core/Filter/LexerTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'tests/units/Core') diff --git a/tests/units/Core/Filter/LexerTest.php b/tests/units/Core/Filter/LexerTest.php index c72231c4..b777531d 100644 --- a/tests/units/Core/Filter/LexerTest.php +++ b/tests/units/Core/Filter/LexerTest.php @@ -202,4 +202,16 @@ class LexerTest extends Base $this->assertSame($expected, $lexer->tokenize('६Δↈ五一')); } + + public function testTokenizeWithMultipleValues() + { + $lexer = new Lexer(); + $lexer->addToken("/^(tag:)/", 'T_TAG'); + + $expected = array( + 'T_TAG' => array('tag 1', 'tag2'), + ); + + $this->assertSame($expected, $lexer->tokenize('tag:"tag 1" tag:tag2')); + } } -- cgit v1.2.3 From a089cd72de82acb95986a630b862a4c3090e3e2a Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Fri, 1 Jul 2016 09:47:10 -0400 Subject: Fixed lexer issue with non word characters --- ChangeLog | 1 + app/Core/Filter/Lexer.php | 2 +- tests/units/Core/Filter/LexerTest.php | 44 +++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) (limited to 'tests/units/Core') diff --git a/ChangeLog b/ChangeLog index 3ea3f2c6..12754948 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,7 @@ Bug fixes: * Fixed broken CSV exports * Fixed identical background color for LetterAvatar on 32bits platforms (Hash greater than PHP_MAX_INT) +* Fixed lexer issue with non word characters Version 1.0.30 -------------- diff --git a/app/Core/Filter/Lexer.php b/app/Core/Filter/Lexer.php index fa5b8d2d..3ff57641 100644 --- a/app/Core/Filter/Lexer.php +++ b/app/Core/Filter/Lexer.php @@ -30,7 +30,7 @@ class Lexer '/^([<=>]{1,2}\w+)/u' => 'T_STRING', '/^([<=>]{1,2}".+")/' => 'T_STRING', '/^("(.+)")/' => 'T_STRING', - '/^(\w+)/u' => 'T_STRING', + '/^(\S+)/u' => 'T_STRING', '/^(#\d+)/' => 'T_STRING', ); diff --git a/tests/units/Core/Filter/LexerTest.php b/tests/units/Core/Filter/LexerTest.php index b777531d..d57a7953 100644 --- a/tests/units/Core/Filter/LexerTest.php +++ b/tests/units/Core/Filter/LexerTest.php @@ -214,4 +214,48 @@ class LexerTest extends Base $this->assertSame($expected, $lexer->tokenize('tag:"tag 1" tag:tag2')); } + + public function testTokenizeWithDash() + { + $lexer = new Lexer(); + $lexer->addToken("/^(test:)/", 'T_TEST'); + + $expected = array( + 'T_TEST' => array('PO-123'), + ); + + $this->assertSame($expected, $lexer->tokenize('test:PO-123')); + + $lexer = new Lexer(); + $lexer->setDefaultToken('myDefaultToken'); + + $expected = array( + 'myDefaultToken' => array('PO-123'), + ); + + $this->assertSame($expected, $lexer->tokenize('PO-123')); + } + + public function testTokenizeWithUnderscore() + { + $lexer = new Lexer(); + $lexer->addToken("/^(test:)/", 'T_TEST'); + + $expected = array( + 'T_TEST' => array('PO_123'), + ); + + $this->assertSame($expected, $lexer->tokenize('test:PO_123')); + + $lexer = new Lexer(); + $lexer->addToken("/^(test:)/", 'T_TEST'); + $lexer->setDefaultToken('myDefaultToken'); + + $expected = array( + 'T_TEST' => array('ABC-123'), + 'myDefaultToken' => array('PO_123'), + ); + + $this->assertSame($expected, $lexer->tokenize('test:ABC-123 PO_123')); + } } -- cgit v1.2.3 From a8a8bfb0afdd105980181a5fa11701028ff5adfe Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 2 Jul 2016 18:23:47 -0400 Subject: Added more unit tests for LDAP user class --- app/Core/Ldap/User.php | 8 ++--- tests/units/Core/Ldap/LdapUserTest.php | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) (limited to 'tests/units/Core') diff --git a/app/Core/Ldap/User.php b/app/Core/Ldap/User.php index 91b48530..4bc1f5f9 100644 --- a/app/Core/Ldap/User.php +++ b/app/Core/Ldap/User.php @@ -116,7 +116,7 @@ class User */ protected function getRole(array $groupIds) { - if ($this->hasGroupsNotConfigured()) { + if (! $this->hasGroupsConfigured()) { return null; } @@ -278,14 +278,14 @@ class User } /** - * Return true if LDAP Group mapping is not configured + * Return true if LDAP Group mapping are configured * * @access public * @return boolean */ - public function hasGroupsNotConfigured() + public function hasGroupsConfigured() { - return !$this->getGroupAdminDn() && !$this->getGroupManagerDn(); + return $this->getGroupAdminDn() || $this->getGroupManagerDn(); } /** diff --git a/tests/units/Core/Ldap/LdapUserTest.php b/tests/units/Core/Ldap/LdapUserTest.php index 505b8a03..143a8c0d 100644 --- a/tests/units/Core/Ldap/LdapUserTest.php +++ b/tests/units/Core/Ldap/LdapUserTest.php @@ -845,4 +845,64 @@ class LdapUserTest extends Base $this->assertTrue($this->user->hasGroupUserFilter()); } + + public function testHasGroupsConfigured() + { + $this->user + ->expects($this->any()) + ->method('getGroupAdminDn') + ->will($this->returnValue('something')); + + $this->user + ->expects($this->any()) + ->method('getGroupManagerDn') + ->will($this->returnValue('something')); + + $this->assertTrue($this->user->hasGroupsConfigured()); + } + + public function testHasGroupAdminDnConfigured() + { + $this->user + ->expects($this->any()) + ->method('getGroupAdminDn') + ->will($this->returnValue('something')); + + $this->user + ->expects($this->any()) + ->method('getGroupManagerDn') + ->will($this->returnValue('')); + + $this->assertTrue($this->user->hasGroupsConfigured()); + } + + public function testHasGroupManagerDnConfigured() + { + $this->user + ->expects($this->any()) + ->method('getGroupAdminDn') + ->will($this->returnValue('')); + + $this->user + ->expects($this->any()) + ->method('getGroupManagerDn') + ->will($this->returnValue('something')); + + $this->assertTrue($this->user->hasGroupsConfigured()); + } + + public function testHasGroupsNotConfigured() + { + $this->user + ->expects($this->any()) + ->method('getGroupAdminDn') + ->will($this->returnValue('')); + + $this->user + ->expects($this->any()) + ->method('getGroupManagerDn') + ->will($this->returnValue('')); + + $this->assertFalse($this->user->hasGroupsConfigured()); + } } -- cgit v1.2.3 From 9496dfdb6df0266b6b7c99c01a4eb9055322b581 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Thu, 14 Jul 2016 11:39:59 -0400 Subject: Make search attributes not case sensitive --- ChangeLog | 1 + app/Core/Filter/LexerBuilder.php | 2 +- tests/units/Core/Filter/LexerBuilderTest.php | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'tests/units/Core') diff --git a/ChangeLog b/ChangeLog index 097ec68e..3fcb6ed6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,7 @@ New features: Improvements: +* Make search attributes not case sensitive * Display TOTP issuer for 2FA * Make sure that the table schema_version use InnoDB for Mysql diff --git a/app/Core/Filter/LexerBuilder.php b/app/Core/Filter/LexerBuilder.php index 7a9a714f..626d7614 100644 --- a/app/Core/Filter/LexerBuilder.php +++ b/app/Core/Filter/LexerBuilder.php @@ -69,7 +69,7 @@ class LexerBuilder foreach ($attributes as $attribute) { $this->filters[$attribute] = $filter; - $this->lexer->addToken(sprintf("/^(%s:)/", $attribute), $attribute); + $this->lexer->addToken(sprintf("/^(%s:)/i", $attribute), $attribute); if ($default) { $this->lexer->setDefaultToken($attribute); diff --git a/tests/units/Core/Filter/LexerBuilderTest.php b/tests/units/Core/Filter/LexerBuilderTest.php index 23726f32..65bb87b9 100644 --- a/tests/units/Core/Filter/LexerBuilderTest.php +++ b/tests/units/Core/Filter/LexerBuilderTest.php @@ -103,4 +103,24 @@ class LexerBuilderTest extends Base $this->assertFalse($builder === $clone); $this->assertFalse($builder->build('test')->getQuery() === $clone->build('test')->getQuery()); } + + public function testBuilderWithMixedCaseSearchAttribute() + { + $project = new ProjectModel($this->container); + $taskCreation = new TaskCreationModel($this->container); + $taskFinder = new TaskFinderModel($this->container); + $query = $taskFinder->getExtendedQuery(); + + $this->assertEquals(1, $project->create(array('name' => 'Project'))); + $this->assertNotFalse($taskCreation->create(array('project_id' => 1, 'title' => 'Test'))); + + $builder = new LexerBuilder(); + $builder->withFilter(new TaskAssigneeFilter()); + $builder->withFilter(new TaskTitleFilter(), true); + $builder->withQuery($query); + $tasks = $builder->build('AsSignEe:nobody')->toArray(); + + $this->assertCount(1, $tasks); + $this->assertEquals('Test', $tasks[0]['title']); + } } -- cgit v1.2.3 From 4364559805245260f89d70d590d0686250aa5f93 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 16 Jul 2016 14:11:14 -0400 Subject: Handle HTTP header X-Real-IP to get IP address --- ChangeLog | 1 + app/Core/Http/Request.php | 1 + tests/units/Core/Http/RequestTest.php | 3 +++ 3 files changed, 5 insertions(+) (limited to 'tests/units/Core') diff --git a/ChangeLog b/ChangeLog index 6c5c5107..64476247 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,7 @@ New features: Improvements: +* Handle header X-Real-IP to get IP address * Display project name for task auto-complete fields * Make search attributes not case sensitive * Display TOTP issuer for 2FA diff --git a/app/Core/Http/Request.php b/app/Core/Http/Request.php index e0df2d3c..2e84958d 100644 --- a/app/Core/Http/Request.php +++ b/app/Core/Http/Request.php @@ -301,6 +301,7 @@ class Request extends Base public function getIpAddress() { $keys = array( + 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', diff --git a/tests/units/Core/Http/RequestTest.php b/tests/units/Core/Http/RequestTest.php index 6fa796f7..1db0100c 100644 --- a/tests/units/Core/Http/RequestTest.php +++ b/tests/units/Core/Http/RequestTest.php @@ -169,6 +169,9 @@ class RequestTest extends Base $request = new Request($this->container, array(), array(), array(), array(), array()); $this->assertEquals('Unknown', $request->getIpAddress()); + $request = new Request($this->container, array('HTTP_X_REAL_IP' => '192.168.1.1,127.0.0.1'), array(), array(), array(), array()); + $this->assertEquals('192.168.1.1', $request->getIpAddress()); + $request = new Request($this->container, array('HTTP_X_FORWARDED_FOR' => '192.168.0.1,127.0.0.1'), array(), array(), array(), array()); $this->assertEquals('192.168.0.1', $request->getIpAddress()); -- cgit v1.2.3 From 3aa0f8574898876518dddf29ced43dd32efa2375 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 16 Jul 2016 19:15:26 -0400 Subject: Fixed search query with multiple assignees (nested OR conditions) --- ChangeLog | 1 + composer.json | 2 +- composer.lock | 14 +++++++------- tests/units/Core/Filter/LexerBuilderTest.php | 26 ++++++++++++++++++++++++++ tests/units/Core/Filter/OrCriteriaTest.php | 5 +++-- 5 files changed, 38 insertions(+), 10 deletions(-) (limited to 'tests/units/Core') diff --git a/ChangeLog b/ChangeLog index 64476247..e87c0965 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,7 @@ Improvements: Bug fixes: +* Fixed search query with multiple assignees (nested OR conditions) * Fixed Markdown editor auto-grow on the task form (Safari) * Fixed compatibility issue with PHP 5.3 for OAuthUserProvider class diff --git a/composer.json b/composer.json index a619dc0a..443fb826 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "eluceo/ical": "0.10.1", "erusev/parsedown" : "1.6.0", "fguillot/json-rpc" : "1.2.1", - "fguillot/picodb" : "1.0.13", + "fguillot/picodb" : "1.0.14", "fguillot/simpleLogger" : "1.0.1", "fguillot/simple-validator" : "1.0.1", "fguillot/simple-queue" : "1.0.1", diff --git a/composer.lock b/composer.lock index a7697470..33c2ca71 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": "77e9464e13331b1dec5c810d1c186ebf", - "content-hash": "0d13e80c805e296f3765cc329d51358a", + "hash": "daa76b43d528f87e3bed91133fdb9259", + "content-hash": "dde1b92fc6f9ca106cf927f4cd141a21", "packages": [ { "name": "christian-riesen/base32", @@ -245,16 +245,16 @@ }, { "name": "fguillot/picodb", - "version": "v1.0.13", + "version": "v1.0.14", "source": { "type": "git", "url": "https://github.com/fguillot/picoDb.git", - "reference": "e8e02cd6a170811eed6c70d1edcbb419818d303a" + "reference": "86a831302ab10af800c83dbe4b3b01c88d5433f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fguillot/picoDb/zipball/e8e02cd6a170811eed6c70d1edcbb419818d303a", - "reference": "e8e02cd6a170811eed6c70d1edcbb419818d303a", + "url": "https://api.github.com/repos/fguillot/picoDb/zipball/86a831302ab10af800c83dbe4b3b01c88d5433f1", + "reference": "86a831302ab10af800c83dbe4b3b01c88d5433f1", "shasum": "" }, "require": { @@ -281,7 +281,7 @@ ], "description": "Minimalist database query builder", "homepage": "https://github.com/fguillot/picoDb", - "time": "2016-07-13 02:11:01" + "time": "2016-07-16 22:59:59" }, { "name": "fguillot/simple-queue", diff --git a/tests/units/Core/Filter/LexerBuilderTest.php b/tests/units/Core/Filter/LexerBuilderTest.php index 65bb87b9..31e237dc 100644 --- a/tests/units/Core/Filter/LexerBuilderTest.php +++ b/tests/units/Core/Filter/LexerBuilderTest.php @@ -8,6 +8,7 @@ use Kanboard\Filter\TaskTitleFilter; use Kanboard\Model\ProjectModel; use Kanboard\Model\TaskCreationModel; use Kanboard\Model\TaskFinderModel; +use Kanboard\Model\UserModel; class LexerBuilderTest extends Base { @@ -123,4 +124,29 @@ class LexerBuilderTest extends Base $this->assertCount(1, $tasks); $this->assertEquals('Test', $tasks[0]['title']); } + + public function testWithOrCriteria() + { + $taskFinder = new TaskFinderModel($this->container); + $taskCreation = new TaskCreationModel($this->container); + $projectModel = new ProjectModel($this->container); + $userModel = new UserModel($this->container); + $query = $taskFinder->getExtendedQuery(); + + $this->assertEquals(2, $userModel->create(array('username' => 'foobar', 'name' => 'Foo Bar'))); + $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); + $this->assertEquals(1, $taskCreation->create(array('title' => 'Test 1', 'project_id' => 1, 'owner_id' => 2))); + $this->assertEquals(2, $taskCreation->create(array('title' => 'Test 2', 'project_id' => 1, 'owner_id' => 1))); + $this->assertEquals(3, $taskCreation->create(array('title' => 'Test 3', 'project_id' => 1, 'owner_id' => 0))); + + $builder = new LexerBuilder(); + $builder->withFilter(new TaskAssigneeFilter()); + $builder->withFilter(new TaskTitleFilter(), true); + $builder->withQuery($query); + $tasks = $builder->build('assignee:admin assignee:foobar')->toArray(); + + $this->assertCount(2, $tasks); + $this->assertEquals('Test 1', $tasks[0]['title']); + $this->assertEquals('Test 2', $tasks[1]['title']); + } } diff --git a/tests/units/Core/Filter/OrCriteriaTest.php b/tests/units/Core/Filter/OrCriteriaTest.php index a46726c3..cf520f36 100644 --- a/tests/units/Core/Filter/OrCriteriaTest.php +++ b/tests/units/Core/Filter/OrCriteriaTest.php @@ -22,8 +22,9 @@ class OrCriteriaTest extends Base $this->assertEquals(2, $userModel->create(array('username' => 'foobar', 'name' => 'Foo Bar'))); $this->assertEquals(1, $projectModel->create(array('name' => 'Test'))); - $this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1, 'owner_id' => 2))); - $this->assertEquals(2, $taskCreation->create(array('title' => 'Test', 'project_id' => 1, 'owner_id' => 1))); + $this->assertEquals(1, $taskCreation->create(array('title' => 'Test 1', 'project_id' => 1, 'owner_id' => 2))); + $this->assertEquals(2, $taskCreation->create(array('title' => 'Test 2', 'project_id' => 1, 'owner_id' => 1))); + $this->assertEquals(3, $taskCreation->create(array('title' => 'Test 3', 'project_id' => 1, 'owner_id' => 0))); $criteria = new OrCriteria(); $criteria->withQuery($query); -- cgit v1.2.3 From 92a5a0f8607e136e42e411a8b7aa9e948d3e3611 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sun, 31 Jul 2016 11:28:33 -0400 Subject: Cleanup events and stuff before processing job in worker --- app/Console/WorkerCommand.php | 1 - app/Core/Action/ActionManager.php | 16 +++++++++++ app/Core/Queue/JobHandler.php | 14 +++++++++- tests/units/Base.php | 7 +++++ tests/units/Core/Action/ActionManagerTest.php | 40 +++++++++++++++++++++++---- 5 files changed, 71 insertions(+), 7 deletions(-) (limited to 'tests/units/Core') diff --git a/app/Console/WorkerCommand.php b/app/Console/WorkerCommand.php index 86727a60..e332624b 100644 --- a/app/Console/WorkerCommand.php +++ b/app/Console/WorkerCommand.php @@ -23,7 +23,6 @@ class WorkerCommand extends BaseCommand protected function execute(InputInterface $input, OutputInterface $output) { - $this->dispatcher->dispatch('app.bootstrap'); $this->queueManager->listen(); } } diff --git a/app/Core/Action/ActionManager.php b/app/Core/Action/ActionManager.php index 1dfd820c..aec9ef02 100644 --- a/app/Core/Action/ActionManager.php +++ b/app/Core/Action/ActionManager.php @@ -139,4 +139,20 @@ class ActionManager extends Base return $this; } + + /** + * Remove all listeners for automated actions + * + * @access public + */ + public function removeEvents() + { + foreach ($this->dispatcher->getListeners() as $eventName => $listeners) { + foreach ($listeners as $listener) { + if (is_array($listener) && $listener[0] instanceof ActionBase) { + $this->dispatcher->removeListener($eventName, $listener); + } + } + } + } } diff --git a/app/Core/Queue/JobHandler.php b/app/Core/Queue/JobHandler.php index 326f3cef..11c1fb69 100644 --- a/app/Core/Queue/JobHandler.php +++ b/app/Core/Queue/JobHandler.php @@ -43,8 +43,8 @@ class JobHandler extends Base try { $className = $payload['class']; - $this->memoryCache->flush(); $this->prepareJobSession($payload['user_id']); + $this->prepareJobEnvironment(); if (DEBUG) { $this->logger->debug(__METHOD__.' Received job => '.$className.' ('.getmypid().')'); @@ -75,4 +75,16 @@ class JobHandler extends Base $this->userSession->initialize($user); } } + + /** + * Flush in-memory caching and specific events + * + * @access protected + */ + protected function prepareJobEnvironment() + { + $this->memoryCache->flush(); + $this->actionManager->removeEvents(); + $this->dispatcher->dispatch('app.bootstrap'); + } } diff --git a/tests/units/Base.php b/tests/units/Base.php index c471ee31..e44223ce 100644 --- a/tests/units/Base.php +++ b/tests/units/Base.php @@ -16,6 +16,11 @@ abstract class Base extends PHPUnit_Framework_TestCase { protected $container; + /** + * @var EventDispatcher + */ + protected $dispatcher; + public function setUp() { date_default_timezone_set('UTC'); @@ -49,6 +54,8 @@ abstract class Base extends PHPUnit_Framework_TestCase new Stopwatch ); + $this->dispatcher = $this->container['dispatcher']; + $this->container['db']->getStatementHandler()->withLogging(); $this->container['logger'] = new Logger(); diff --git a/tests/units/Core/Action/ActionManagerTest.php b/tests/units/Core/Action/ActionManagerTest.php index e7c2071f..4878c0c9 100644 --- a/tests/units/Core/Action/ActionManagerTest.php +++ b/tests/units/Core/Action/ActionManagerTest.php @@ -96,7 +96,7 @@ class ActionManagerTest extends Base $actions = $actionManager->getAvailableActions(); $actionManager->attachEvents(); - $this->assertEmpty($this->container['dispatcher']->getListeners()); + $this->assertEmpty($this->dispatcher->getListeners()); $this->assertEquals(1, $projectModel->create(array('name' =>'test'))); $this->assertEquals(1, $actionModel->create(array( @@ -107,7 +107,7 @@ class ActionManagerTest extends Base ))); $actionManager->attachEvents(); - $listeners = $this->container['dispatcher']->getListeners(TaskModel::EVENT_CREATE); + $listeners = $this->dispatcher->getListeners(TaskModel::EVENT_CREATE); $this->assertCount(1, $listeners); $this->assertInstanceOf(get_class($actionTaskAssignColorColumn), $listeners[0][0]); @@ -148,7 +148,7 @@ class ActionManagerTest extends Base $actionManager->attachEvents(); - $listeners = $this->container['dispatcher']->getListeners(TaskModel::EVENT_MOVE_COLUMN); + $listeners = $this->dispatcher->getListeners(TaskModel::EVENT_MOVE_COLUMN); $this->assertCount(1, $listeners); $this->assertInstanceOf(get_class($actionTaskAssignColorColumn), $listeners[0][0]); @@ -158,7 +158,6 @@ class ActionManagerTest extends Base public function testThatEachListenerAreDifferentInstance() { $projectModel = new ProjectModel($this->container); - $projectUserRoleModel = new ProjectUserRoleModel($this->container); $actionModel = new ActionModel($this->container); $actionTaskAssignColorColumn = new TaskAssignColorColumn($this->container); $actionManager = new ActionManager($this->container); @@ -183,7 +182,7 @@ class ActionManagerTest extends Base $actionManager->attachEvents(); - $listeners = $this->container['dispatcher']->getListeners(TaskModel::EVENT_MOVE_COLUMN); + $listeners = $this->dispatcher->getListeners(TaskModel::EVENT_MOVE_COLUMN); $this->assertCount(2, $listeners); $this->assertFalse($listeners[0][0] === $listeners[1][0]); @@ -193,4 +192,35 @@ class ActionManagerTest extends Base $this->assertEquals(1, $listeners[1][0]->getParam('column_id')); $this->assertEquals('red', $listeners[1][0]->getParam('color_id')); } + + public function testRemoveEvents() + { + $projectModel = new ProjectModel($this->container); + $actionModel = new ActionModel($this->container); + $actionTaskAssignColorColumn = new TaskAssignColorColumn($this->container); + $actionManager = new ActionManager($this->container); + $actionManager->register($actionTaskAssignColorColumn); + + $actions = $actionManager->getAvailableActions(); + + $this->assertEquals(1, $projectModel->create(array('name' =>'test'))); + $this->assertEquals(1, $actionModel->create(array( + 'project_id' => 1, + 'event_name' => TaskModel::EVENT_CREATE, + 'action_name' => key($actions), + 'params' => array('column_id' => 1, 'color_id' => 'red'), + ))); + + $actionManager->attachEvents(); + $this->dispatcher->addListener(TaskModel::EVENT_CREATE, function () {}); + + $listeners = $this->dispatcher->getListeners(TaskModel::EVENT_CREATE); + $this->assertCount(2, $listeners); + + $actionManager->removeEvents(); + + $listeners = $this->dispatcher->getListeners(TaskModel::EVENT_CREATE); + $this->assertCount(1, $listeners); + $this->assertNotInstanceOf(get_class($actionTaskAssignColorColumn), $listeners[0]); + } } -- cgit v1.2.3 From 4ffaba2ba0dd6b5810adea1916080c3b645f3d29 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 13 Aug 2016 14:23:53 -0400 Subject: Add reference hooks --- ChangeLog | 1 + app/Core/Filter/LexerBuilder.php | 2 +- app/Core/Plugin/Hook.php | 17 ++++++++++ app/Formatter/BoardFormatter.php | 11 ++++--- app/Pagination/SubtaskPagination.php | 5 ++- app/Pagination/TaskPagination.php | 5 ++- doc/plugin-hooks.markdown | 25 +++++++++++++++ tests/units/Core/Plugin/HookTest.php | 62 ++++++++++++++++++++++-------------- 8 files changed, 97 insertions(+), 31 deletions(-) (limited to 'tests/units/Core') diff --git a/ChangeLog b/ChangeLog index 68537a3a..25ce7eea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ Version 1.0.33 (unreleased) Improvements: +* Add "reference" hooks * Show project name in task forms * Convert vanilla CSS to SASS diff --git a/app/Core/Filter/LexerBuilder.php b/app/Core/Filter/LexerBuilder.php index 626d7614..e3ab725b 100644 --- a/app/Core/Filter/LexerBuilder.php +++ b/app/Core/Filter/LexerBuilder.php @@ -51,7 +51,7 @@ class LexerBuilder */ public function __construct() { - $this->lexer = new Lexer; + $this->lexer = new Lexer(); $this->queryBuilder = new QueryBuilder(); } diff --git a/app/Core/Plugin/Hook.php b/app/Core/Plugin/Hook.php index ade69150..ca197937 100644 --- a/app/Core/Plugin/Hook.php +++ b/app/Core/Plugin/Hook.php @@ -96,4 +96,21 @@ class Hook return null; } + + /** + * Hook with reference + * + * @access public + * @param string $hook + * @param mixed $param + * @return mixed + */ + public function reference($hook, &$param) + { + foreach ($this->getListeners($hook) as $listener) { + $listener($param); + } + + return $param; + } } diff --git a/app/Formatter/BoardFormatter.php b/app/Formatter/BoardFormatter.php index 350dde6c..df443a52 100644 --- a/app/Formatter/BoardFormatter.php +++ b/app/Formatter/BoardFormatter.php @@ -44,6 +44,13 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface { $swimlanes = $this->swimlaneModel->getSwimlanes($this->projectId); $columns = $this->columnModel->getAll($this->projectId); + + if (empty($swimlanes) || empty($columns)) { + return array(); + } + + $this->hook->reference('formatter:board:query', $this->query); + $tasks = $this->query ->eq(TaskModel::TABLE.'.project_id', $this->projectId) ->asc(TaskModel::TABLE.'.position') @@ -52,10 +59,6 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface $task_ids = array_column($tasks, 'id'); $tags = $this->taskTagModel->getTagsByTasks($task_ids); - if (empty($swimlanes) || empty($columns)) { - return array(); - } - return BoardSwimlaneFormatter::getInstance($this->container) ->withSwimlanes($swimlanes) ->withColumns($columns) diff --git a/app/Pagination/SubtaskPagination.php b/app/Pagination/SubtaskPagination.php index f0cd6148..c55d0fb4 100644 --- a/app/Pagination/SubtaskPagination.php +++ b/app/Pagination/SubtaskPagination.php @@ -26,11 +26,14 @@ class SubtaskPagination extends Base */ public function getDashboardPaginator($user_id, $method, $max) { + $query = $this->subtaskModel->getUserQuery($user_id, array(SubtaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS)); + $this->hook->reference('pagination:dashboard:subtask:query', $query); + return $this->paginator ->setUrl('DashboardController', $method, array('pagination' => 'subtasks', 'user_id' => $user_id)) ->setMax($max) ->setOrder(TaskModel::TABLE.'.id') - ->setQuery($this->subtaskModel->getUserQuery($user_id, array(SubtaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))) + ->setQuery($query) ->calculateOnlyIf($this->request->getStringParam('pagination') === 'subtasks'); } } diff --git a/app/Pagination/TaskPagination.php b/app/Pagination/TaskPagination.php index a395ab84..5fe986e7 100644 --- a/app/Pagination/TaskPagination.php +++ b/app/Pagination/TaskPagination.php @@ -25,11 +25,14 @@ class TaskPagination extends Base */ public function getDashboardPaginator($user_id, $method, $max) { + $query = $this->taskFinderModel->getUserQuery($user_id); + $this->hook->reference('pagination:dashboard:task:query', $query); + return $this->paginator ->setUrl('DashboardController', $method, array('pagination' => 'tasks', 'user_id' => $user_id)) ->setMax($max) ->setOrder(TaskModel::TABLE.'.id') - ->setQuery($this->taskFinderModel->getUserQuery($user_id)) + ->setQuery($query) ->calculateOnlyIf($this->request->getStringParam('pagination') === 'tasks'); } } diff --git a/doc/plugin-hooks.markdown b/doc/plugin-hooks.markdown index 787c62df..5e01e93a 100644 --- a/doc/plugin-hooks.markdown +++ b/doc/plugin-hooks.markdown @@ -115,6 +115,31 @@ List of asset Hooks: - `template:layout:css` - `template:layout:js` + +Reference hooks +--------------- + +Reference hooks are passing a variable by reference. + +Example: + +```php +$this->hook->on('formatter:board:query', function (\PicoDb\Table &query) { + $query->eq('color_id', 'red'); +}); +``` + +The code above will show only tasks in red on the board. + +List of reference hooks: + +| Hook | Description | +|--------------------------------------------|---------------------------------------------------------------| +| `formatter:board:query` | Alter database query before rendering board | +| `pagination:dashboard:task:query` | Alter database query for tasks pagination on the dashboard | +| `pagination:dashboard:subtask:query` | Alter database query for subtasks pagination on the dashboard | + + Template Hooks -------------- diff --git a/tests/units/Core/Plugin/HookTest.php b/tests/units/Core/Plugin/HookTest.php index d1c139b3..acadede0 100644 --- a/tests/units/Core/Plugin/HookTest.php +++ b/tests/units/Core/Plugin/HookTest.php @@ -8,89 +8,103 @@ class HookTest extends Base { public function testGetListeners() { - $h = new Hook; - $this->assertEmpty($h->getListeners('myhook')); + $hook = new Hook; + $this->assertEmpty($hook->getListeners('myhook')); - $h->on('myhook', 'A'); - $h->on('myhook', 'B'); + $hook->on('myhook', 'A'); + $hook->on('myhook', 'B'); - $this->assertEquals(array('A', 'B'), $h->getListeners('myhook')); + $this->assertEquals(array('A', 'B'), $hook->getListeners('myhook')); } public function testExists() { - $h = new Hook; - $this->assertFalse($h->exists('myhook')); + $hook = new Hook; + $this->assertFalse($hook->exists('myhook')); - $h->on('myhook', 'A'); + $hook->on('myhook', 'A'); - $this->assertTrue($h->exists('myhook')); + $this->assertTrue($hook->exists('myhook')); } public function testMergeWithNoBinding() { - $h = new Hook; + $hook = new Hook; $values = array('A', 'B'); - $result = $h->merge('myhook', $values, array('p' => 'c')); + $result = $hook->merge('myhook', $values, array('p' => 'c')); $this->assertEquals($values, $result); } public function testMergeWithBindings() { - $h = new Hook; + $hook = new Hook; $values = array('A', 'B'); $expected = array('A', 'B', 'c', 'D'); - $h->on('myhook', function ($p) { + $hook->on('myhook', function ($p) { return array($p); }); - $h->on('myhook', function () { + $hook->on('myhook', function () { return array('D'); }); - $result = $h->merge('myhook', $values, array('p' => 'c')); + $result = $hook->merge('myhook', $values, array('p' => 'c')); $this->assertEquals($expected, $result); $this->assertEquals($expected, $values); } public function testMergeWithBindingButReturningBadData() { - $h = new Hook; + $hook = new Hook; $values = array('A', 'B'); $expected = array('A', 'B'); - $h->on('myhook', function () { + $hook->on('myhook', function () { return 'string'; }); - $result = $h->merge('myhook', $values); + $result = $hook->merge('myhook', $values); $this->assertEquals($expected, $result); $this->assertEquals($expected, $values); } public function testFirstWithNoBinding() { - $h = new Hook; + $hook = new Hook; - $result = $h->first('myhook', array('p' => 2)); + $result = $hook->first('myhook', array('p' => 2)); $this->assertEquals(null, $result); } public function testFirstWithMultipleBindings() { - $h = new Hook; + $hook = new Hook; - $h->on('myhook', function ($p) { + $hook->on('myhook', function ($p) { return $p + 1; }); - $h->on('myhook', function ($p) { + $hook->on('myhook', function ($p) { return $p; }); - $result = $h->first('myhook', array('p' => 3)); + $result = $hook->first('myhook', array('p' => 3)); $this->assertEquals(4, $result); } + + public function testHookWithReference() + { + $hook = new Hook(); + + $hook->on('myhook', function (&$p) { + $p = 2; + }); + + $param = 123; + $result = $hook->reference('myhook', $param); + $this->assertSame(2, $result); + $this->assertSame(2, $param); + } } -- cgit v1.2.3