From dc92f2f8eb4b2b3d5e93fd82a5ab151991c1fa3d Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 29 Mar 2013 22:13:21 -0400 Subject: [PATCH] CRM-12193 - Add pick() function randomly choose among options (provided that permission/component filters apply) ---------------------------------------- * CRM-12193: In-app fundraising for CiviCRM http://issues.civicrm.org/jira/browse/CRM-12193 --- CRM/Core/CommunityMessages.php | 29 ++++++- CRM/Core/Permission.php | 15 ++++ .../CRM/Core/CommunityMessagesTest.php | 84 +++++++++++++++++++ tests/phpunit/CiviTest/CiviUnitTestCase.php | 15 ++++ 4 files changed, 141 insertions(+), 2 deletions(-) diff --git a/CRM/Core/CommunityMessages.php b/CRM/Core/CommunityMessages.php index 21b3dc7344..bf7ef91cb8 100644 --- a/CRM/Core/CommunityMessages.php +++ b/CRM/Core/CommunityMessages.php @@ -31,6 +31,7 @@ class CRM_Core_CommunityMessages { const DEFAULT_MESSAGES_URL = 'http://alert.civicrm.org/alert?prot=1&ver={ver}&uf={uf}&sid={sid}'; + const DEFAULT_PERMISSION = 'administer CiviCRM'; /** * Default time to wait before retrying @@ -134,8 +135,32 @@ class CRM_Core_CommunityMessages { * @param array $components * @return NULL|array */ - public function pick($permChecker, $components) { - throw new Exception('not implemented'); + public function pick() { + $document = $this->getDocument(); + $messages = array(); + foreach ($document['messages'] as $message) { + if (!isset($message['perms'])) { + $message['perms'] = array(self::DEFAULT_PERMISSION); + } + if (!CRM_Core_Permission::checkAnyPerm($message['perms'])) { + continue; + } + + if (isset($message['components'])) { + $enabled = array_keys(CRM_Core_Component::getEnabledComponents()); + if (count(array_intersect($enabled, $message['components'])) == 0) { + continue; + } + } + + $messages[] = $message; + } + if (empty($messages)) { + return NULL; + } + + $idx = rand(0, count($messages) - 1); + return $messages[$idx]; } /** diff --git a/CRM/Core/Permission.php b/CRM/Core/Permission.php index 4fd201a112..5197212579 100644 --- a/CRM/Core/Permission.php +++ b/CRM/Core/Permission.php @@ -77,6 +77,21 @@ class CRM_Core_Permission { return $config->userPermissionClass->check( $str ); } + /** + * Determine if any one of the permissions strings applies to current user + * + * @param array $perms + * @return bool + */ + public static function checkAnyPerm($perms) { + foreach ($perms as $perm) { + if (CRM_Core_Permission::check($perm)) { + return TRUE; + } + } + return FALSE; + } + /** * Given a group/role array, check for access requirements * diff --git a/tests/phpunit/CRM/Core/CommunityMessagesTest.php b/tests/phpunit/CRM/Core/CommunityMessagesTest.php index 96736fd19a..fccf92c302 100644 --- a/tests/phpunit/CRM/Core/CommunityMessagesTest.php +++ b/tests/phpunit/CRM/Core/CommunityMessagesTest.php @@ -87,6 +87,40 @@ class CRM_Core_CommunityMessagesTest extends CiviUnitTestCase { ), )) ), + 'two-messages' => array( + CRM_Utils_HttpClient::STATUS_OK, + json_encode(array( + 'ttl' => 600, + 'retry' => 600, + 'messages' => array( + array( + 'markup' => '

One

', + 'components' => array('CiviMail'), + ), + array( + 'markup' => '

Two

', + 'components' => array('CiviMail'), + ), + ), + )) + ), + 'two-messages-halfbadcomp' => array( + CRM_Utils_HttpClient::STATUS_OK, + json_encode(array( + 'ttl' => 600, + 'retry' => 600, + 'messages' => array( + array( + 'markup' => '

One

', + 'components' => array('NotARealComponent'), + ), + array( + 'markup' => '

Two

', + 'components' => array('CiviMail'), + ), + ), + )) + ), ); } return self::$webResponses; @@ -252,6 +286,56 @@ class CRM_Core_CommunityMessagesTest extends CiviUnitTestCase { $this->assertEquals(strtotime('2013-03-01 12:20:02'), $doc4['expires']); } + /** + * Randomly pick among two options + */ + public function testPick_rand() { + $communityMessages = new CRM_Core_CommunityMessages( + $this->cache, + $this->expectOneHttpRequest(self::$webResponses['two-messages']) + ); + $doc1 = $communityMessages->getDocument(); + $this->assertEquals('

One

', $doc1['messages'][0]['markup']); + $this->assertEquals('

Two

', $doc1['messages'][1]['markup']); + + // randomly pick many times + $trials = 40; + $freq = array(); // array($message => $count) + for ($i = 0; $i < $trials; $i++) { + $message = $communityMessages->pick(); + $freq[$message['markup']]++; + } + + // assert the probabilities + $this->assertApproxEquals(0.5, $freq['

One

'] / $trials, 0.2); + $this->assertApproxEquals(0.5, $freq['

Two

'] / $trials, 0.2); + $this->assertEquals($trials, $freq['

One

'] + $freq['

Two

']); + } + + /** + * When presented with two options using component filters, always + * choose the one which references an active component. + */ + public function testPick_componentFilter() { + $communityMessages = new CRM_Core_CommunityMessages( + $this->cache, + $this->expectOneHttpRequest(self::$webResponses['two-messages-halfbadcomp']) + ); + $doc1 = $communityMessages->getDocument(); + $this->assertEquals('

One

', $doc1['messages'][0]['markup']); + $this->assertEquals('

Two

', $doc1['messages'][1]['markup']); + + // randomly pick many times + $trials = 10; + $freq = array(); // array($message => $count) + for ($i = 0; $i < $trials; $i++) { + $message = $communityMessages->pick(); + $freq[$message['markup']]++; + } + + $this->assertEquals($trials, $freq['

Two

']); + } + /** * Generate a mock HTTP client with the expectation that it is never called. * diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index 1abe16eae6..1b8304330c 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -552,6 +552,21 @@ class CiviUnitTestCase extends PHPUnit_Extensions_Database_TestCase { $this->assertEquals($e, $a); } + /** + * Assert that two numbers are approximately equal + * + * @param int|float $expected + * @param int|float $actual + * @param int|float $tolerance + * @param string $message + */ + function assertApproxEquals($expected, $actual, $tolerance, $message = NULL) { + if ($message === NULL) { + $message = sprintf("approx-equals: expected=[%.3f] actual=[%.3f] tolerance=[%.3f]", $expected, $actual, $tolerance); + } + $this->assertTrue(abs($actual - $expected) < $tolerance, $message); + } + function assertAttributesEquals($expectedValues, $actualValues, $message = NULL) { foreach ($expectedValues as $paramName => $paramValue) { if (isset($actualValues[$paramName])) { -- 2.25.1