jenkins-bot has submitted this change and it was merged.

Change subject: DataValidator uses GatewayAdapter object
......................................................................


DataValidator uses GatewayAdapter object

This makes it possible to change validation based on adapter logic such
as country controlling allowable currencies, etc.

Includes a basic test of validation.  TODO: expand to cover all validations.

Change-Id: Icb347e2a1a77d359ff604049481d8dca0693e91e
---
M extras/custom_filters/filters/ip_velocity/ip_velocity.body.php
M extras/session_velocity/session_velocity.body.php
M gateway_common/DataValidator.php
M gateway_common/DonationData.php
A tests/GatewayValidationTest.php
M tests/includes/test_gateway/TestingGenericAdapter.php
6 files changed, 125 insertions(+), 128 deletions(-)

Approvals:
  Ejegg: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/extras/custom_filters/filters/ip_velocity/ip_velocity.body.php 
b/extras/custom_filters/filters/ip_velocity/ip_velocity.body.php
index 76c7989..65227a1 100644
--- a/extras/custom_filters/filters/ip_velocity/ip_velocity.body.php
+++ b/extras/custom_filters/filters/ip_velocity/ip_velocity.body.php
@@ -23,12 +23,12 @@
                $user_ip = $this->gateway_adapter->getData_Unstaged_Escaped( 
'user_ip' );
                
                //first, handle the whitelist / blacklist before you do 
anything else. 
-               if ( DataValidator::ip_is_listed( $user_ip, 'IPWhitelist' ) ){
+               if ( DataValidator::ip_is_listed( $user_ip, 
$this->gateway_adapter->getGlobal( 'IPWhitelist' ) ) ) {
                        $this->gateway_adapter->debugarray[] = "IP present in 
whitelist.";
                        $this->cfo->addRiskScore( 0, 'IPWhitelist' );
                        return true;
                }
-               if ( DataValidator::ip_is_listed( $user_ip, 'IPBlacklist' ) ){
+               if ( DataValidator::ip_is_listed( $user_ip, 
$this->gateway_adapter->getGlobal( 'IPBlacklist' ) ) ) {
                        $this->gateway_adapter->debugarray[] = "IP present in 
blacklist.";
                        $this->cfo->addRiskScore( 
$this->gateway_adapter->getGlobal( 'IPVelocityFailScore' ), 'IPBlacklist' );
                        return true;
diff --git a/extras/session_velocity/session_velocity.body.php 
b/extras/session_velocity/session_velocity.body.php
index c1dd701..cebd5df 100644
--- a/extras/session_velocity/session_velocity.body.php
+++ b/extras/session_velocity/session_velocity.body.php
@@ -61,7 +61,7 @@
                        return true;
                }
                $gateway_adapter->debugarray[] = 'Session Velocity onFilter 
hook!';
-               return self::singleton( $gateway_adapter )->filter( 
$gateway_adapter );
+               return self::singleton( $gateway_adapter )->filter();
        }
 
        /**
@@ -72,13 +72,13 @@
         *
         * @return bool Hook return, false stops processing of the hook chain
         */
-       private function filter( &$gateway_adapter ) {
+       private function filter() {
 
                $user_ip = $this->gateway_adapter->getData_Unstaged_Escaped( 
'user_ip' );
 
                // Determine IP status before doing anything complex
-               $wl = DataValidator::ip_is_listed( $user_ip, 'IPWhitelist', 
$gateway_adapter->getIdentifier() );
-               $bl = DataValidator::ip_is_listed( $user_ip, 'IPBlacklist', 
$gateway_adapter->getIdentifier() );
+               $wl = DataValidator::ip_is_listed( $user_ip, 
$this->gateway_adapter->getGlobal( 'IPWhitelist' ) );
+               $bl = DataValidator::ip_is_listed( $user_ip, 
$this->gateway_adapter->getGlobal( 'IPBlacklist' ) );
 
                if ( $wl ) {
                        $this->gateway_adapter->debugarray[] = 
"SessionVelocity: IP present in whitelist.";
@@ -95,12 +95,12 @@
                }
 
                // Obtain some useful information
-               $gateway = $gateway_adapter->getIdentifier();
-               $transaction = $gateway_adapter->getCurrentTransaction();
+               $gateway = $this->gateway_adapter->getIdentifier();
+               $transaction = $this->gateway_adapter->getCurrentTransaction();
                $cRequestTime = $_SERVER['REQUEST_TIME'];
 
-               $decayRate = $this->getVar( 'DecayRate', $transaction, 
$gateway_adapter );
-               $threshold = $this->getVar( 'Threshold', $transaction, 
$gateway_adapter );
+               $decayRate = $this->getVar( 'DecayRate', $transaction );
+               $threshold = $this->getVar( 'Threshold', $transaction );
 
                // Initialize the filter
                if ( !array_key_exists( self::SESS_ROOT, $_SESSION ) ) {
@@ -122,7 +122,7 @@
                // Update the filter if it's stale
                if ( $cRequestTime != $lastTime ) {
                        $score = max( 0, $score - ( ( $cRequestTime - $lastTime 
) * $decayRate ) );
-                       $score += $this->getVar( 'HitScore', $transaction, 
$gateway_adapter );
+                       $score += $this->getVar( 'HitScore', $transaction );
 
                        // Store the results
                        
$_SESSION[self::SESS_ROOT][$gateway][$transaction][$this::SESS_SCORE] = $score;
@@ -148,14 +148,13 @@
         *
         * @param string    $baseVar  The root name of the variable
         * @param string    $txn      The name of the transaction
-        * @param object    $gateway  The current gateway object
         *
         * @return mixed    The contents of the configuration variable
         */
-       private function getVar( $baseVar, $txn, &$gateway ) {
-               $var = $gateway->getGlobal( 'SessionVelocity_' . $txn . '_' . 
$baseVar );
+       private function getVar( $baseVar, $txn ) {
+               $var = $this->gateway_adapter->getGlobal( 'SessionVelocity_' . 
$txn . '_' . $baseVar );
                if ( !isset( $var ) ) {
-                       $var = $gateway->getGlobal( 'SessionVelocity_' . 
$baseVar );
+                       $var = $this->gateway_adapter->getGlobal( 
'SessionVelocity_' . $baseVar );
                }
 
                return $var;
diff --git a/gateway_common/DataValidator.php b/gateway_common/DataValidator.php
index 96f80b4..c090e08 100644
--- a/gateway_common/DataValidator.php
+++ b/gateway_common/DataValidator.php
@@ -9,6 +9,7 @@
  * order to use it any/everywhere. 
  * 
  * @author khorn
+ * @author awight
  */
 class DataValidator {
        
@@ -39,21 +40,7 @@
                'order_id',
                'numAttempt'
        );
-       
-       /**
-        * $gateway_classes
-        * @var array A list of all possible gateway classes. 
-        * FIXME: get rid of this
-        */
-       protected static $gateway_classes = array(
-               'globalcollect' => 'GlobalCollectAdapter',
-               'payflowpro' => 'PayflowProAdapter',
-               'paypal' => 'PaypalAdapter',
-               'adyen' => 'AdyenAdapter',
-               'amazon' => 'AmazonAdapter',
-               'worldpay' => 'WorldPayAdapter'
-       );
-       
+
        /**
         * $card_types
         * @var array A list of SOME card types we recognize
@@ -276,6 +263,7 @@
         * wfLangSpecificFallback - returns the text of the first existant 
message
         * in the requested language. If no messages are found in that 
language, the
         * function returns the first existant fallback message.
+        * TODO: Belongs somewhere very else.
         *
         * @param string $language the code of the requested language
         * @param array $msg_keys
@@ -322,7 +310,7 @@
         * the main DonationInterface Form class to display. The array will be 
empty
         * if no errors were generated and everything passed OK.
         */
-       public static function validate( $gateway, $data, $check_not_empty = 
array()  ){
+       public static function validate( GatewayAdapter $gateway, $data, 
$check_not_empty = array()  ){
                //return the array of errors that should be generated on 
validate.
                //just the same way you'd do it if you were a form passing the 
error array around. 
                
@@ -334,8 +322,6 @@
                 * Third: Do validation that depends on multiple fields (making 
sure you 
                 * validated that all the required fields exist on step 1, 
regardless of 
                 * $check_not_empty)
-                * 
-                * So, we need to know what we're about to do for #3 before we 
actually do #1. 
                 * 
                 * $check_not_empty should contain an array of values that need 
to be populated. 
                 * One likely candidate for a source there, is the required 
stomp fields as defined in DonationData. 
@@ -458,11 +444,13 @@
                                switch ( $function ){
                                        case 'validate_amount':
                                                if ( 
self::checkValidationPassed( array( 'currency_code', 'gateway' ), $instructions 
) ){
-                                                       $result = 
$self::$function( $data[$field], $data['currency_code'], $data['gateway'] );
+                                                       $priceFloor = 
$gateway->getGlobal( 'PriceFloor' );
+                                                       $priceCeiling = 
$gateway->getGlobal( 'PriceCeiling' );
+                                                       $result = 
$self::$function( $data[$field], $data['currency_code'], $priceFloor, 
$priceCeiling );
                                                } //otherwise, just don't do 
the validation. The other stuff will be complaining already. 
                                                break;
                                        case 'validate_currency_code':
-                                               $result = $self::$function( 
$data[$field], $data['gateway'] );
+                                               $result = $self::$function( 
$data[$field], $gateway->getCurrencies() );
                                                break;
                                        case 'validate_card_type':
                                                //the contingent field in this 
case isn't strictly required, so this is going to look funny. 
@@ -487,8 +475,6 @@
                                throw new MWException( __FUNCTION__ . " BAD 
PROGRAMMER. No $function function. ('calculated' rule for $field)" );
                        }
                }
-//             error_log( __FUNCTION__ . " " . print_r( $instructions, true ) 
);
-//             error_log( print_r( $errors, true ) );
                return $errors;
        }
        
@@ -572,29 +558,20 @@
 
        /**
         * validate_amount
+        *
         * Determines if the $value passed in is a valid amount. 
-        * NOTE: You will need to make sure that currency_code is populated 
before 
-        * you get here. 
         * @param string $value The piece of data that is supposed to be an 
amount. 
-        * @param string $currency_code Valid amounts depend on there being a 
-        * currency code also. This also needs to be passed in. 
-        * @param string $gateway The gateway needs to be provided so we can 
-        * determine that gateway's current price floor and ceiling.  
+        * @param string $currency_code The amount was given in this currency.
+        * @param float $priceFloor Minimum valid amount (USD).
+        * @param float $priceCeiling Maximum valid amount (USD).
+        *
         * @return boolean True if $value is a valid amount, otherwise false.  
         */
-       protected static function validate_amount( $value, $currency_code, 
$gateway ){
+       protected static function validate_amount( $value, $currency_code, 
$priceFloor, $priceCeiling ) {
                if ( !$value || !$currency_code || !is_numeric( $value ) ) {
                        return false;
                }
-               
-               // check amount
-               $gateway_class = self::getGatewayClass($gateway);
-               if ( !$gateway_class ){
-                       return false;
-               }
-               
-               $priceFloor = $gateway_class::getGlobal( 'PriceFloor' );
-               $priceCeiling = $gateway_class::getGlobal( 'PriceCeiling' );
+
                if ( !preg_match( '/^\d+(\.(\d+)?)?$/', $value ) ||
                        ( ( float ) self::convert_to_usd( $currency_code, 
$value ) < ( float ) $priceFloor ||
                        ( float ) self::convert_to_usd( $currency_code, $value 
) > ( float ) $priceCeiling ) ) {
@@ -604,20 +581,12 @@
                return true;
        }
 
-       protected static function validate_currency_code( $value, $gateway ) {
+       protected static function validate_currency_code( $value, 
$acceptedCurrencies ) {
                if ( !$value ) {
                        return false;
                }
 
-               $gateway_class = self::getGatewayClass($gateway);
-               if ( !$gateway_class ){
-                       return false;
-               }
-
-               // FIXME: we should be checking currencies using the live 
gateway
-               // object, the result is often dependent on payment 
method/submethod,
-               // country, and so on.
-               return in_array( $value, $gateway_class::getCurrencies() );
+               return in_array( $value, $acceptedCurrencies );
        }
        
        /**
@@ -667,6 +636,7 @@
         * @return boolean True if $value is a valid boolean, otherwise false.  
         */
        protected static function validate_boolean( $value ){
+               // FIXME: this doesn't do the strict comparison we intended.  
'hello' would match the "case true" statement.
                switch ($value) {
                        case 0:
                        case '0':
@@ -706,14 +676,11 @@
         * @return boolean True if $value is a valid gateway, otherwise false
         */
        protected static function validate_gateway( $value ){
-               if ( self::getGatewayClass( $value ) ){
-                       return true;
-               }
-               
-               return false;
+               global $wgDonationInterfaceEnabledGateways;
+
+               return in_array( $value, $wgDonationInterfaceEnabledGateways, 
true );
        }
-       
-       
+
        /**
         * validate_not_empty
         * Checks to make sure that the $value is present in the $data array, 
and not null or an empty string. 
@@ -899,23 +866,7 @@
                }
                return( ( $sum % 10 ) == 0 );
        }
-       
-       /**
-        * getGatewayClass
-        * This exists to enable things like logging to the correct gateway, 
and 
-        * retrieving gateway-specific globals. 
-        * @param string $gateway The gateway identifier. 
-        * @return string The name of the gateway class associated with that 
-        * identifier, or false if none exists. 
-        */
-       protected static function getGatewayClass( $gateway ) {
-               if ( array_key_exists( $gateway, self::$gateway_classes ) && 
class_exists( self::$gateway_classes[$gateway] ) ){
-                       return self::$gateway_classes[$gateway];
-               }
-               return false;
-       }
-       
-       
+
        /**
         * Convert an amount for a particular currency to an amount in USD
         *
@@ -939,7 +890,7 @@
                if ( array_key_exists( $code, $rates ) ) {
                        $usd_amount = $amount / $rates[$code];
                } else {
-                       $usd_amount = $amount;
+                       throw new Exception( 'Bad programmer!  Bad currency 
made it too far through the portcullis' );
                }
                return $usd_amount;
        }
@@ -1010,51 +961,22 @@
        }
 
        /**
-        * Eventually, this function should pull from here and memcache.
-        * @staticvar array $blacklist A cached and expanded blacklist
+        * Check whether IP matches a block list
+        *
+        * TODO: We might want to store the expanded list in memcache.
+        *
         * @param string $ip The IP addx we want to check
-        * @param string $list_name The global list, ostensibly full of IP 
addresses,
-        * that we want to check against.
-        * @param string $gateway The gateway we're concerned with. Only 
matters if,
-        * for instance, $wgDonationInterfaceIPBlacklist is different from
-        * $wgGlobalcollectGatewayIPBlacklist for some silly reason.
+        * @param array $ip_list IP list to check against
         * @throws MWException
         * @return bool
         */
-       public static function ip_is_listed( $ip, $list_name, $gateway = '' ) {
-               //cache this mess
-               static $ip_list_cache = array();
-               $globalIPLists = array(
-                       'IPWhitelist',
-                       'IPBlacklist',
-               );
-               
-               if ( !in_array( $list_name, $globalIPLists ) ){
-                       throw new MWException( __FUNCTION__ . " BAD PROGRAMMER. 
No recognized global list of IPs called $list_name. Do better." );
+       public static function ip_is_listed( $ip, $ip_list ) {
+               $expanded = array();
+               foreach ( $ip_list as $address ){
+                       $expanded = array_merge( $expanded, 
self::expandIPBlockToArray( $address ) );
                }
-               
-               $class = self::getGatewayClass( $gateway );
-               if ( !$class ){
-                       $class = 'GatewayAdapter';
-               }
-               
-               if ( !array_key_exists( $class, $ip_list_cache ) || 
!array_key_exists( $list_name, $ip_list_cache[$class] ) ){
-                       //go get it and expand the block entries
-                       $list = $class::getGlobal( $list_name );
-                       $expanded = array();
-                       foreach ( $list as $address ){
-                               $expanded = array_merge( $expanded, 
self::expandIPBlockToArray( $address ) );
-                       }
-                       $ip_list_cache[$class][$list_name] = $expanded;
-                       //TODO: This seems like an excellent time to stash this 
expanded 
-                       //thing in memcache. Later, we can look for that value 
earlier. Yup.
-               }
-               
-               if ( in_array( $ip, $ip_list_cache[$class][$list_name] ) ){
-                       return true;
-               } else {
-                       return false;
-               }
+
+               return in_array( $ip, $expanded, true );
        }
        
        /**
diff --git a/gateway_common/DonationData.php b/gateway_common/DonationData.php
index 3fc1dc8..35cc646 100644
--- a/gateway_common/DonationData.php
+++ b/gateway_common/DonationData.php
@@ -315,6 +315,8 @@
         * be called multiple times against the same array.
         */
        protected function normalize() {
+               // FIXME: there's a ghost invocation during DonationData 
construction.
+               // This condition should actually be "did data come from 
anywhere?"
                if ( !empty( $this->normalized ) ) {
                        $updateCtRequired = 
$this->handleContributionTrackingID(); // Before Order ID
                        $this->setNormalizedOrderIDs();
diff --git a/tests/GatewayValidationTest.php b/tests/GatewayValidationTest.php
new file mode 100644
index 0000000..1aeb1dd
--- /dev/null
+++ b/tests/GatewayValidationTest.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Wikimedia Foundation
+ *
+ * LICENSE
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/**
+ * @group Fundraising
+ * @group DonationInterface
+ * @group GatewayPage
+ */
+class GatewayValidationTest extends MediaWikiTestCase {
+
+       protected $page;
+       protected $adapter;
+
+       public function setUp() {
+               parent::setUp();
+
+               $this->setMwGlobals( array(
+                       'wgDonationInterfaceEnabledGateways' => array( 
'donation' ), // base class.  awkward.
+                       'wgDonationInterfacePriceFloor' => 2.00,
+               ) );
+
+               TestingGenericAdapter::$acceptedCurrencies[] = 'USD';
+
+               $this->page = new TestingGatewayPage();
+               $this->adapter = new TestingGenericAdapter();
+               $this->page->adapter = $this->adapter;
+               parent::setUp();
+       }
+
+       public function testPassesValidation() {
+               $this->adapter->addData( array(
+                       'amount' => '2.00',
+                       'country' => 'US',
+                       'currency_code' => 'USD',
+               ) );
+
+               $this->page->validateForm();
+
+               $this->assertTrue( $this->adapter->validatedOK() );
+       }
+
+       public function testLowAmountError() {
+               $this->adapter->addData( array(
+                       'amount' => '1.99',
+                       'country' => 'US',
+                       'currency_code' => 'USD',
+               ) );
+
+               $this->page->validateForm();
+
+               $this->assertFalse( $this->adapter->validatedOK() );
+
+               $errors = $this->adapter->getValidationErrors();
+               $this->assertArrayHasKey( 'amount', $errors );
+       }
+}
diff --git a/tests/includes/test_gateway/TestingGenericAdapter.php 
b/tests/includes/test_gateway/TestingGenericAdapter.php
index c92d3b8..a70a404 100644
--- a/tests/includes/test_gateway/TestingGenericAdapter.php
+++ b/tests/includes/test_gateway/TestingGenericAdapter.php
@@ -29,6 +29,8 @@
        public $revalidateCount = 0;
        public static $fakeGlobals = array();
 
+       public static $acceptedCurrencies = array();
+
        public function revalidate($check_not_empty = array()) {
                if ( $this->errorsForRevalidate ) {
                        $fakeErrors = 
$this->errorsForRevalidate[$this->revalidateCount];
@@ -95,6 +97,7 @@
        }
 
        public static function getCurrencies() {
+               return TestingGenericAdapter::$acceptedCurrencies;
        }
 
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/184010
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Icb347e2a1a77d359ff604049481d8dca0693e91e
Gerrit-PatchSet: 14
Gerrit-Project: mediawiki/extensions/DonationInterface
Gerrit-Branch: master
Gerrit-Owner: Awight <[email protected]>
Gerrit-Reviewer: AndyRussG <[email protected]>
Gerrit-Reviewer: Awight <[email protected]>
Gerrit-Reviewer: Ejegg <[email protected]>
Gerrit-Reviewer: Katie Horn <[email protected]>
Gerrit-Reviewer: Ssmith <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to