r103512 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r103511‎ | r103512 | r103513 >
Date:21:54, 17 November 2011
Author:khorn
Status:ok
Tags:
Comment:
Modified paths:
  • /branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts (added) (history)
  • /branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts/orphan_adapter.php (added) (history)
  • /branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts/orphanlogs (added) (history)
  • /branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts/orphans.php (modified) (history)

Diff [purge]

Index: branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts/orphans.php
@@ -0,0 +1,235 @@
 2+<?php
 3+//If you want to use this script, you will have to add the following line to LocalSettings.php:
 4+//$wgAutoloadClasses['GlobalCollectOrphanAdapter'] = $IP . '/extensions/DonationInterface/globalcollect_gateway/scripts/orphan_adapter.php';
 5+
 6+//TODO: Something that is not specific to anybody's install, here.
 7+global $IP;
 8+if ( !isset($IP) ) {
 9+ $IP = '/var/www/wikimedia-dev';
 10+}
 11+require_once( "$IP/maintenance/Maintenance.php" );
 12+
 13+class GlobalCollectOrphanRectifier extends Maintenance {
 14+
 15+ protected $killfiles = array();
 16+ protected $order_ids = array();
 17+ protected $max_per_execute = 3;
 18+
 19+
 20+ function execute(){
 21+
 22+ $order_ids = file('orphanlogs/order_ids.txt', FILE_SKIP_EMPTY_LINES);
 23+ foreach ($order_ids as $key=>$val){
 24+ $order_ids[$key] = trim($val);
 25+ }
 26+ foreach ($order_ids as $id){
 27+ $this->order_ids[$id] = $id; //easier to unset this way.
 28+ }
 29+ $outstanding_count = count($this->order_ids);
 30+ echo "Order ID count: " . $outstanding_count . "\n";
 31+
 32+ $files = $this->getAllLogFileNames();
 33+ $payments = array();
 34+ foreach ($files as $file){
 35+ if (count($payments) < $this->max_per_execute){
 36+ $file_array = $this->getLogfileLines( $file );
 37+ $payments = array_merge($this->findTransactionLines($file_array), $payments);
 38+ if (count($payments) === 0){
 39+ $this->killfiles[] = $file;
 40+ echo print_r($this->killfiles, true);
 41+ }
 42+ }
 43+ }
 44+
 45+ $data = array(
 46+ 'wheeee' => 'yes'
 47+ );
 48+
 49+ $adapter = new GlobalCollectOrphanAdapter(array('external_data' => $data));
 50+ $adapter->setCurrentTransaction('INSERT_ORDERWITHPAYMENT');
 51+ $var_map = $adapter->defineVarMap();
 52+
 53+ $xml = new DomDocument;
 54+
 55+ //fields that have generated notices if they're not there.
 56+ $additional_fields = array(
 57+ 'card_num',
 58+ 'comment',
 59+ 'size',
 60+ 'utm_medium',
 61+ 'utm_campaign',
 62+ 'referrer',
 63+ 'mname',
 64+ 'fname2',
 65+ 'lname2',
 66+ 'street2',
 67+ 'city2',
 68+ 'state2',
 69+ 'country2',
 70+ 'zip2',
 71+ );
 72+
 73+
 74+ foreach ($payments as $key => $payment_data){
 75+ $xml->loadXML($payment_data['xml']);
 76+ $parsed = $adapter->getResponseData($xml);
 77+ $payments[$key]['parsed'] = $parsed;
 78+ $payments[$key]['unstaged'] = $adapter->unstage_data($parsed);
 79+ $payments[$key]['unstaged']['contribution_tracking_id'] = $payments[$key]['contribution_tracking_id'];
 80+ $payments[$key]['unstaged']['i_order_id'] = $payments[$key]['unstaged']['order_id'];
 81+ foreach ($additional_fields as $val){
 82+ if (!array_key_exists($val, $payments[$key]['unstaged'])){
 83+ $payments[$key]['unstaged'][$val] = null;
 84+ }
 85+ }
 86+ }
 87+
 88+ // ADDITIONAL: log out what you did here, to... somewhere.
 89+ // Preferably *before* you rewrite the Order ID file.
 90+
 91+ //we may need to unset some hooks out here. Like... recaptcha. Makes no sense.
 92+ $i = 0;
 93+ foreach($payments as $payment_data){
 94+ if ($i < $this->max_per_execute){
 95+ ++$i;
 96+ $adapter->loadDataAndReInit($payment_data['unstaged']);
 97+ $results = $adapter->do_transaction('Confirm_CreditCard');
 98+ if ($results['status']){
 99+ $adapter->log( $payment_data['unstaged']['contribution_tracking_id'] . ": FINAL: " . $results['action']);
 100+ unset($this->order_ids[$payment_data['unstaged']['order_id']]);
 101+ } else {
 102+ $adapter->log( $payment_data['unstaged']['contribution_tracking_id'] . ": ERROR: " . $results['message']);
 103+ if (strpos($results['message'], "GET_ORDERSTATUS reports that the payment is already complete.")){
 104+ unset($this->order_ids[$payment_data['unstaged']['order_id']]);
 105+ }
 106+ }
 107+ echo $results['message'] . "\n";
 108+ }
 109+ }
 110+
 111+ if ($outstanding_count != count($this->order_ids)){
 112+ $this->rewriteOrderIds();
 113+ }
 114+ }
 115+
 116+ function getAllLogFileNames(){
 117+ $files = array();
 118+ if ($handle = opendir(dirname(__FILE__) . '/orphanlogs/')){
 119+ while ( ($file = readdir($handle)) !== false ){
 120+ if (trim($file, '.') != '' && $file != 'order_ids.txt' && $file != '.svn'){
 121+ $files[] = dirname(__FILE__) . '/orphanlogs/' . $file;
 122+ }
 123+ }
 124+ }
 125+ closedir($handle);
 126+ return $files;
 127+ }
 128+
 129+ function findTransactionLines($file){
 130+ $lines = array();
 131+ $orders = array();
 132+ $contrib_id_finder = array();
 133+ foreach ($file as $line_no=>$line_data){
 134+ if (strpos($line_data, '<XML><REQUEST><ACTION>INSERT_ORDERWITHPAYMENT') === 0){
 135+ $lines[$line_no] = $line_data;
 136+ } elseif (strpos($line_data, 'Raw XML Response')){
 137+ $contrib_id_finder[] = $line_data;
 138+ } elseif (strpos(trim($line_data), '<ORDERID>') === 0){
 139+ $contrib_id_finder[] = trim($line_data);
 140+ }
 141+ }
 142+
 143+ $order_ids = $this->order_ids;
 144+ foreach ($lines as $line_no=>$line_data){
 145+ if (count($orders) < $this->max_per_execute){
 146+ $pos1 = strpos($line_data, '<ORDERID>') + 9;
 147+ $pos2 = strpos($line_data, '</ORDERID>');
 148+ if ($pos2 > $pos1){
 149+ $tmp = substr($line_data, $pos1, $pos2-$pos1);
 150+ if (isset($order_ids[$tmp])){
 151+ $orders[$tmp] = trim($line_data);
 152+ unset($order_ids[$tmp]);
 153+ }
 154+ }
 155+ }
 156+ }
 157+
 158+ //reverse the array, so we find the last instance first.
 159+ $contrib_id_finder = array_reverse($contrib_id_finder);
 160+ foreach ($orders as $order_id => $xml){
 161+ $contribution_tracking_id = '';
 162+ $finder = array_search("<ORDERID>$order_id</ORDERID>", $contrib_id_finder);
 163+
 164+ //now search forward (which is actually backward) to the "Raw XML" line, so we can get the contribution_tracking_id
 165+ //TODO: Some kind of (in)sanity check for this. Just because we've found it one step backward doesn't mean...
 166+ //...but it's kind of good. For now.
 167+ $explode_me = false;
 168+ while (!$explode_me){
 169+ ++$finder;
 170+ if (strpos($contrib_id_finder[$finder], "Raw XML Response")){
 171+ $explode_me = $contrib_id_finder[$finder];
 172+ }
 173+ }
 174+ if (strlen($explode_me)){
 175+ $explode_me = explode(': ', $explode_me);
 176+ $contribution_tracking_id = trim($explode_me[1]);
 177+ $orders[$order_id] = array(
 178+ 'xml' => $xml,
 179+ 'contribution_tracking_id' => $contribution_tracking_id,
 180+ );
 181+ }
 182+ }
 183+
 184+ return $orders;
 185+ }
 186+
 187+ function rewriteOrderIds() {
 188+ $file = fopen('orphanlogs/order_ids.txt', 'w');
 189+ $outstanding_orders = implode("\n", $this->order_ids);
 190+ fwrite($file, $outstanding_orders);
 191+ fclose($file);
 192+ }
 193+
 194+ function getLogfileLines( $file ){
 195+ $array = array(); //surprise!
 196+ $array = file($file, FILE_SKIP_EMPTY_LINES);
 197+ //now, check about 50 lines to make sure we're not seeing any of that #012, #015 crap.
 198+ $checkcount = 50;
 199+ if (count($array) < $checkcount){
 200+ $checkcount = count($array);
 201+ }
 202+ $convert = false;
 203+ for ($i=0; $i<$checkcount; ++$i){
 204+ if( strpos($array[$i], '#012') || strpos($array[$i], '#015') ){
 205+ $convert = true;
 206+ break;
 207+ }
 208+ }
 209+ if ($convert) {
 210+ $array2 = array();
 211+ foreach ($array as $line){
 212+ if (strpos($line, '#012')){
 213+ $line = str_replace('#012', "\n", $line);
 214+ }
 215+ if (strpos($line, '#015') ){
 216+ $line = str_replace('#015', "\r", $line);
 217+ }
 218+ $array2[] = $line;
 219+ }
 220+ $newfile = implode("\n", $array2);
 221+
 222+ $handle = fopen($file, 'w');
 223+ fwrite($handle, $newfile);
 224+ fclose($handle);
 225+ $array = file($file, FILE_SKIP_EMPTY_LINES);
 226+ }
 227+
 228+ return $array;
 229+ }
 230+
 231+}
 232+
 233+$maintClass = "GlobalCollectOrphanRectifier";
 234+require_once( "$IP/maintenance/doMaintenance.php" );
 235+
 236+
Property changes on: branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts/orphans.php
___________________________________________________________________
Added: svn:eol-style
1237 + native
Property changes on: branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts/orphanlogs
___________________________________________________________________
Added: svn:ignore
2238 + globalcollect.2
globalcollect.1
globalcollect
globalcollect.6
globalcollect.5
globalcollect.4
2011-11-11:17:59:48-globalcollect
order_ids.txt
globalcollect.3
globalcollect.7
Index: branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts/orphan_adapter.php
@@ -0,0 +1,205 @@
 2+<?php
 3+
 4+class GlobalCollectOrphanAdapter extends GlobalCollectAdapter {
 5+
 6+ //Data we know to be good, that we always want to re-assert after a load or an addData.
 7+ //so far: order_id, i_order_id, and the utm data we pull from contribution tracking.
 8+ protected $hard_data = array();
 9+
 10+ public function unstage_data( $data = array(), $final = true ){
 11+ $unstaged = array();
 12+ foreach ( $data as $key=>$val ){
 13+ if (is_array($val)){
 14+ $unstaged += $this->unstage_data( $val, false );
 15+ } else {
 16+ if (array_key_exists($key, $this->var_map)){
 17+ //run the unstage data functions.
 18+ $unstaged[$this->var_map[$key]] = $val;
 19+ //this would be EXTREMELY bad to put in the regular adapter.
 20+ $this->staged_data[$this->var_map[$key]] = $val;
 21+ } else {
 22+ //$unstaged[$key] = $val;
 23+ }
 24+ }
 25+ }
 26+ if ($final){
 27+ $this->stageData('response');
 28+ }
 29+ foreach ($unstaged as $key=>$val){
 30+ $unstaged[$key] = $this->staged_data[$key];
 31+ }
 32+ return $unstaged;
 33+ }
 34+
 35+ public function loadDataAndReInit( $data ){
 36+ $this->batch = true; //or the hooks will accumulate badness.
 37+
 38+ //re-init all these arrays, because this is a batch thing.
 39+ $this->hard_data = array();
 40+ $this->transaction_results = array();
 41+ $this->raw_data = array();
 42+ $this->staged_data = array();
 43+
 44+ $this->hard_data['order_id'] = $data['order_id'];
 45+ $this->hard_data['i_order_id'] = $data['order_id'];
 46+
 47+ $this->dataObj = new DonationData( get_called_class(), false, $data );
 48+
 49+ $this->raw_data = $this->dataObj->getData();
 50+
 51+ $this->hard_data = array_merge( $this->hard_data, $this->getUTMInfoFromDB() );
 52+ $this->reAddHardData();
 53+
 54+ $this->staged_data = $this->raw_data;
 55+
 56+ $this->setPostDefaults();
 57+ $this->defineTransactions();
 58+ $this->defineErrorMap();
 59+ $this->defineVarMap();
 60+ $this->defineDataConstraints();
 61+ $this->defineAccountInfo();
 62+ $this->defineReturnValueMap();
 63+
 64+ $this->stageData();
 65+
 66+ //have to do this again here.
 67+ $this->reAddHardData();
 68+ }
 69+
 70+ public function addData($dataArray){
 71+ parent::addData($dataArray);
 72+ $this->reAddHardData();
 73+ }
 74+
 75+ private function reAddHardData(){
 76+ //anywhere else, and this would constitute abuse of the system.
 77+ //so don't do it.
 78+ foreach ($this->hard_data as $key => $val){
 79+ $this->raw_data[$key] = $val;
 80+ $this->staged_data[$key] = $val;
 81+ }
 82+ }
 83+
 84+ public function do_transaction($transaction){
 85+ switch ($transaction){
 86+ case 'SET_PAYMENT':
 87+ case 'CANCEL_PAYMENT':
 88+ self::log($this->getData_Raw('contribution_tracking_id') . ": CVV: " . $this->getData_Raw('cvv_result') . ": AVS: " . $this->getData_Raw('avs_result'));
 89+ //and then go on, unless you're testing, in which case:
 90+// return "NOPE";
 91+// break;
 92+ default:
 93+ return parent::do_transaction($transaction);
 94+ break;
 95+ }
 96+ }
 97+
 98+ public static function log( $msg, $log_level = LOG_INFO, $nothing = null ) {
 99+ $identifier = 'orphans:' . self::getIdentifier() . "_gateway_trxn";
 100+
 101+ // if we're not using the syslog facility, use wfDebugLog
 102+ if ( !self::getGlobal( 'UseSyslog' ) ) {
 103+ wfDebugLog( $identifier, $msg );
 104+ return;
 105+ }
 106+
 107+ // otherwise, use syslogging
 108+ openlog( $identifier, LOG_ODELAY, LOG_SYSLOG );
 109+ syslog( $log_level, $msg );
 110+ closelog();
 111+ }
 112+
 113+ public function getUTMInfoFromDB(){
 114+
 115+ $db = ContributionTrackingProcessor::contributionTrackingConnection();
 116+
 117+ if ( !$db ) {
 118+ die("There is something terribly wrong with your Contribution Tracking database. fixit.");
 119+ return null;
 120+ }
 121+
 122+ $ctid = $this->getData_Raw('contribution_tracking_id');
 123+
 124+ $data = array();
 125+
 126+ // if contrib tracking id is not already set, we need to insert the data, otherwise update
 127+ if ( $ctid ) {
 128+ $res = $db->select( 'contribution_tracking',
 129+ array(
 130+ 'utm_source',
 131+ 'utm_campaign',
 132+ 'utm_medium',
 133+ 'ts'
 134+ ),
 135+ array('id' => $ctid)
 136+ );
 137+ foreach ($res as $thing){
 138+ $data['utm_source'] = $thing->utm_source;
 139+ $data['utm_campaign'] = $thing->utm_campaign;
 140+ $data['utm_medium'] = $thing->utm_medium;
 141+ $data['ts'] = $thing->ts;
 142+ $msg = '';
 143+ foreach ($data as $key => $val){
 144+ $msg .= "$key = $val ";
 145+ }
 146+ $this->log("$ctid: Found UTM Data. $msg");
 147+ echo $msg;
 148+ return $data;
 149+ }
 150+ }
 151+
 152+ //if we got here, we can't find anything else...
 153+ $this->log("$ctid: FAILED to find UTM Source value. Using default.");
 154+ return $data;
 155+ }
 156+
 157+
 158+ /**
 159+ * Copying this here because it's the fastest way to bring in an actual timestamp.
 160+ */
 161+ protected function doStompTransaction() {
 162+ if ( !$this->getGlobal( 'EnableStomp' ) ){
 163+ return;
 164+ }
 165+ $this->debugarray[] = "Attempting Stomp Transaction!";
 166+ $hook = '';
 167+
 168+ $status = $this->getTransactionWMFStatus();
 169+ switch ( $status ) {
 170+ case 'complete':
 171+ $hook = 'gwStomp';
 172+ break;
 173+ case 'pending':
 174+ case 'pending-poke':
 175+ $hook = 'gwPendingStomp';
 176+ break;
 177+ }
 178+ if ( $hook === '' ) {
 179+ $this->debugarray[] = "No Stomp Hook Found for WMF_Status $status";
 180+ return;
 181+ }
 182+
 183+
 184+ if (!is_null($this->getData_Raw('ts'))){
 185+ $timestamp = strtotime($this->getData_Raw('ts')); //I hate that this works.
 186+ } else {
 187+ $timestamp = time();
 188+ }
 189+
 190+ // send the thing.
 191+ $transaction = array(
 192+ 'response' => $this->getTransactionMessage(),
 193+ 'date' => $timestamp,
 194+ 'gateway_txn_id' => $this->getTransactionGatewayTxnID(),
 195+ //'language' => '',
 196+ );
 197+ $transaction += $this->getData_Raw();
 198+
 199+ try {
 200+ wfRunHooks( $hook, array( $transaction ) );
 201+ } catch ( Exception $e ) {
 202+ self::log( "STOMP ERROR. Could not add message. " . $e->getMessage() , LOG_CRIT );
 203+ }
 204+ }
 205+
 206+}
\ No newline at end of file
Property changes on: branches/fundraising/deployment/payments_1.17/extensions/DonationInterface/globalcollect_gateway/scripts/orphan_adapter.php
___________________________________________________________________
Added: svn:eol-style
1207 + native

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r103024Preliminary steps toward a command-line solution for finding donations which ...khorn20:43, 14 November 2011
r103076More (but still preliminary) work toward a command-line solution for finding ...khorn23:35, 14 November 2011
r103246Lots more work on the GlobalCollect command-line orphan rectifier....khorn22:23, 15 November 2011
r103288GlobalCollect command-line orphan rectifier: Very near completion. (Intention...khorn02:18, 16 November 2011
r103385GlobalCollect command-line orphan rectifier: As near as I can tell, the first...khorn21:19, 16 November 2011
r103416GlobalCollect command-line orphan rectifier: More small tweaks....khorn23:41, 16 November 2011
r103491GlobalCollect command-line orphan rectifier: Adding in yet more data from the...khorn18:57, 17 November 2011
r103499GlobalCollect command-line orphan rectifier: Bugfix, because I'm hella dumb.khorn19:34, 17 November 2011
r103501GlobalCollect command-line orphan rectifier: Fixing the loops that check that...khorn20:17, 17 November 2011
r103506GlobalCollect command-line orphan rectifier: addressing r103288 fixme.khorn20:35, 17 November 2011

Status & tagging log