Ejegg has submitted this change and it was merged.

Change subject: (FR #1855) Refactor import hook to lower level
......................................................................


(FR #1855) Refactor import hook to lower level

Change-Id: Iad4da4aab1cbca206b3a66b11023e928f0b4312e
---
M phpunit.xml
M sites/all/modules/large_donation/large_donation.module
A sites/all/modules/large_donation/templates/html/notification.en.html
A sites/all/modules/large_donation/tests/LargeDonationTest.php
A sites/all/modules/wmf_campaigns/templates/html/notification.en.html
A sites/all/modules/wmf_campaigns/tests/WmfCampaignTest.php
M sites/all/modules/wmf_campaigns/wmf_campaigns.module
M sites/all/modules/wmf_communication/tests/TestMailer.php
8 files changed, 287 insertions(+), 153 deletions(-)

Approvals:
  Ejegg: Looks good to me, approved



diff --git a/phpunit.xml b/phpunit.xml
index eb56baa..d09e965 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -4,6 +4,9 @@
     bootstrap="sites/default/bootstrap-phpunit.php">
 
     <testsuites>
+      <testsuite name="large_donation tests">
+        <directory>sites/all/modules/large_donation/tests</directory>
+      </testsuite>
       <!-- FIXME: need to mock currency conversion
       <testsuite name="offline2civicrm tests">
         <directory>sites/all/modules/offline2civicrm/tests</directory>
@@ -15,6 +18,9 @@
       <testsuite name="recurring_globalcollect tests">
         <directory>sites/all/modules/recurring_globalcollect/tests</directory>
       </testsuite>
+      <testsuite name="wmf_campaigns tests">
+        <directory>sites/all/modules/wmf_campaigns/tests</directory>
+      </testsuite>
       <testsuite name="wmf_civicrm tests">
         <directory>sites/all/modules/wmf_civicrm/tests/phpunit</directory>
       </testsuite>
diff --git a/sites/all/modules/large_donation/large_donation.module 
b/sites/all/modules/large_donation/large_donation.module
index 62a77e8..ac12e3d 100644
--- a/sites/all/modules/large_donation/large_donation.module
+++ b/sites/all/modules/large_donation/large_donation.module
@@ -1,5 +1,8 @@
 <?php
 
+use wmf_communication\Mailer;
+use wmf_communication\Templating;
+
 /**
  * Implementation of hook_menu().
  */
@@ -63,40 +66,25 @@
 }
 
 /**
- * This hook is called from the module queue2civicrm in the function:
- * queue2civicrm_import().
+ * Implements hook_civicrm_post
  */
-function large_donation_queue2civicrm_import( $contribution_info ) {
+function large_donation_civicrm_post( $action, $type, $id, &$contribution ) {
+    switch ( $action ) {
+    case 'create':
+        if ( $type === 'Contribution' ) {
+            $large_donation_amount = floatval( variable_get( 
'large_donation_amount', 0.00 ) );
 
-  $contribution_id = $contribution_info[ 'contribution_id' ];
+            if ( $contribution->total_amount >= $large_donation_amount ) {
+                watchdog( 'large_donation', "Notifying of large donation, 
contribution: {$contribution->id}" );
 
-  $large_donation_amount = (float) variable_get('large_donation_amount', 0.00);
-
-  $gross = isset( $contribution_info['msg']['gross'] ) ?  (float) 
$contribution_info['msg']['gross'] : 0.00;
-
-  $currency = isset( $contribution_info['msg']['currency'] ) ? 
$contribution_info['msg']['currency'] : '';
-
-  $date = isset( $contribution_info['msg']['date'] ) ? 
$contribution_info['msg']['date'] : NULL;
-
-  if ( empty( $contribution_id ) ) {
-
-    watchdog('large_donation', 'Contribution id is empty!');
-
-  } elseif ( empty( $large_donation_amount ) ) {
-
-    watchdog('large_donation', 'Large donation threshold amount is not set 
up!');
-
-  } elseif ( exchange_rate_convert( $currency, $gross, $date ) >= 
$large_donation_amount ) {
-
-    watchdog('large_donation', 'Calling large donation function for 
contribution: ' . $contribution_info['contribution_id'] . '<pre>' . 
check_plain(print_r($contribution_info, TRUE)) . '</pre>');
-
-    large_donation_notification_send( $contribution_info );
-
-  } else {
-
-    watchdog('large_donation', 'Donation amount [ ' . $gross . ' ' . $currency 
. ' ] was not above the threshold [ ' . $large_donation_amount . ' ]');
-
-  }
+                large_donation_notification_send( $contribution );
+            } else {
+                watchdog('large_donation', "Donation amount 
{$contribution->total_amount} was not above the threshold 
[{$large_donation_amount}]");
+            }
+        }
+        break;
+    default:
+    }
 }
 
 /**
@@ -107,92 +95,54 @@
  *
  * No personally identifiable information should be included.
  *
- * @param array $contribution_info
+ * @param array $contribution
  */
-function large_donation_notification_send( $contribution_info ){
+function large_donation_notification_send( $contribution ) {
+    $contribution_link = CRM_Utils_System::url(
+        'civicrm/contact/view',
+        array(
+            'selectedChild' => 'contribute',
+            'cid' => $contribution->contact_id,
+            'reset' => 1,
+        ),
+        true,
+        'Contributions'
+    );
 
-  $site_url = CIVICRM_UF_BASEURL . base_path();
+    $to = variable_get('large_donation_notifymail', '');
 
-  $to = variable_get('large_donation_notifymail', '');
+    $params = array(
+        'threshold' => floatval( variable_get( 'large_donation_amount', 0.00 ) 
),
+        'contribution' => $contribution,
+        'contribution_link' => $contribution_link,
+    );
 
-  $large_donation_amount = (float) variable_get('large_donation_amount', 0.00);
+    if ( !$to ) {
+        watchdog( 'large_donation', 'Notification recipient address is not set 
up!', NULL, WATCHDOG_ERROR );
+        return;
+    }
 
-  $contact_id = isset( $contribution_info['contact_id'] ) ? 
$contribution_info['contact_id'] : '';
+    $mailer = Mailer::getDefault();
 
-  $link = $site_url . 
'?q=civicrm/contact/view&reset=1&selectedChild=contribute&cid=' . $contact_id . 
'#Contributions';
-
-  $contribution_id = isset( $contribution_info['contribution_id'] ) ? 
$contribution_info['contribution_id'] : '';
-
-  $gross = isset( $contribution_info['msg']['gross'] ) ?  (float) 
$contribution_info['msg']['gross'] : 0.00;
-
-  $currency = isset( $contribution_info['msg']['currency'] ) ? 
$contribution_info['msg']['currency'] : '';
-
-  $payment_method = isset( $contribution_info['msg']['payment_method'] ) ? 
$contribution_info['msg']['payment_method'] : '';
-
-  if ($to != ''){
-
-    $message = '';
-
-    $message .= 'To whom it may concern:';
-    $message .= PHP_EOL;
-    $message .= PHP_EOL;
-    $message .= 'A large donation was made >= ' . $large_donation_amount . ' ' 
. $currency;
-    $message .= PHP_EOL;
-    $message .= PHP_EOL;
-    $message .= 'contact_id: ' . $contact_id;
-    $message .= PHP_EOL;
-    $message .= 'contribution_id: ' . $contribution_id;
-    $message .= PHP_EOL;
-    $message .= 'currency: ' . $currency;
-    $message .= PHP_EOL;
-    $message .= 'gross: ' . $gross;
-    $message .= PHP_EOL;
-    $message .= 'payment_method: ' . $payment_method;
-
-    $message .= PHP_EOL;
-    $message .= PHP_EOL;
-    $message .= 'Contact contribution in CiviCRM:';
-    $message .= PHP_EOL;
-    $message .= PHP_EOL;
-    $message .= $link;
-    $message .= PHP_EOL;
-    $message .= PHP_EOL;
-
-    $message .= 'You may need to examine this donation.';
-
-       $path = variable_get('wmf_common_phpmailer_location', '');
-    require_once(implode(DIRECTORY_SEPARATOR, array($path, 
'class.phpmailer.php')));
-
-    $mail = new PHPMailer( true );
+    $template = new Templating( __DIR__ . '/templates', 'notification', 'en', 
$params, 'html' );
+    $message = $template->render();
 
     try {
-        $mail->set('Charset','utf-8');
-
-        $to = preg_split('/\\s*[,\\n]\\s*/', $to, -1, PREG_SPLIT_NO_EMPTY);
-               foreach ( $to as $addx ){
-               $mail->AddAddress( trim( $addx ) );
-               }
-
-        $mail->SetFrom( '[email protected]', 'WMF CiviCRM-Bot' );
-
-        $mail->Subject = 'WMF - large donation: ' . $gross . ' ' . $currency;
-
-        $mail->AltBody = $message;
-        $mail->MsgHTML( nl2br( $message ) );
-        $mail->Send();
+        $email = array(
+            'to' => preg_split( '/\\s*[,\\n]\\s*/', $to, -1, 
PREG_SPLIT_NO_EMPTY ),
+            'from_address' => '[email protected]',
+            'from_name' => 'Large Donation Bot',
+            'subject' => "WMF - large donation: 
\${$contribution->total_amount}",
+            'html' => $message,
+        );
+        $mailer->send( $email );
 
         $email_success = true;
-    } catch (phpmailerException $e) {
-        watchdog('large_donation', 'Sending large donation message failed for 
contribution (2): ' . $contribution_id . '<pre>' . 
check_plain(print_r($contribution_info, TRUE)) . "\n\n" . $e->errorMessage() . 
'</pre>', array(), WATCHDOG_ERROR);
-    } catch (Exception $e) {
-        watchdog('large_donation', 'Sending large donation message failed for 
contribution (3): ' . $contribution_id . '<pre>' . 
check_plain(print_r($contribution_info, TRUE)) . "\n\n" . $e->getMessage() . 
'</pre>', array(), WATCHDOG_ERROR);
+    } catch ( Exception $e ) {
+        watchdog('large_donation', 'Sending large donation message failed for 
contribution: ' . $contribution_id . '<pre>' . 
check_plain(print_r($contribution, TRUE)) . "\n\n" . $e->getMessage() . 
'</pre>', array(), WATCHDOG_ERROR);
     }
-  } else {
-    watchdog('large_donation', 'Notification recipient address is not set 
up!');
-  }
 
-  if ( $email_success ) {
-    watchdog('large_donation', 'A large donation notification was sent to: ' . 
$to);
-  }
+    if ( $email_success ) {
+        watchdog('large_donation', 'A large donation notification was sent to: 
' . $to);
+    }
 }
-
diff --git 
a/sites/all/modules/large_donation/templates/html/notification.en.html 
b/sites/all/modules/large_donation/templates/html/notification.en.html
new file mode 100644
index 0000000..3edc28b
--- /dev/null
+++ b/sites/all/modules/large_donation/templates/html/notification.en.html
@@ -0,0 +1,17 @@
+<p>To whom it may concern:</p>
+
+<p>A large donation was made (over {{ threshold }} USD):</p>
+
+<p>contact_id: {{ contribution.contact_id }}</p>
+
+<p>contribution_id: {{ contribution.id }}</p>
+
+<p>converted amount: {{ contribution.total_amount }} USD</p>
+
+<p>original amount: {{ contribution.source }}</p>
+
+<p>Contact contribution in CiviCRM:</p>
+
+<p><a href="{{ contribution_link|raw }}">{{ contribution_link|raw }}</a></p>
+
+<p>You may need to examine this donation.</p>
diff --git a/sites/all/modules/large_donation/tests/LargeDonationTest.php 
b/sites/all/modules/large_donation/tests/LargeDonationTest.php
new file mode 100644
index 0000000..8596678
--- /dev/null
+++ b/sites/all/modules/large_donation/tests/LargeDonationTest.php
@@ -0,0 +1,62 @@
+<?php
+
+use wmf_communication\TestMailer;
+
+class LargeDonationTest extends BaseWmfDrupalPhpUnitTestCase {
+    function setUp() {
+        parent::setUp();
+        civicrm_initialize();
+
+        TestMailer::setup();
+
+        $this->original_large_donation_amount = variable_get( 
'large_donation_amount', null );
+        $this->original_large_donation_notifymail = variable_get( 
'large_donation_notifymail', null );
+        $this->threshold = 100;
+        variable_set( 'large_donation_amount', $this->threshold );
+        variable_set( 'large_donation_notifymail', '[email protected]' );
+
+        $result = civicrm_api3( 'Contact', 'create', array(
+            'contact_type' => 'Individual',
+            'first_name' => 'Testes',
+        ) );
+        $this->contact_id = $result['id'];
+    }
+
+    function tearDown() {
+        variable_set( 'large_donation_amount', 
$this->original_large_donation_amount );
+        variable_set( 'large_donation_notifymail', 
$this->original_large_donation_notifymail );
+        parent::tearDown();
+    }
+
+    function testUnderThreshold() {
+        $result = civicrm_api3( 'Contribution', 'create', array(
+            'contact_id' => $this->contact_id,
+            'contribution_type' => 'Cash',
+            'currency' => 'USD',
+            'payment_instrument' => 'Credit Card',
+            'total_amount' => $this->threshold - 0.01,
+            'trxn_id' => 'TEST_GATEWAY ' . mt_rand(),
+        ) );
+
+        $this->assertEquals( 0, TestMailer::countMailings() );
+    }
+
+    function testAboveThreshold() {
+        $amount = $this->threshold + 0.01;
+        $result = civicrm_api3( 'Contribution', 'create', array(
+            'contact_id' => $this->contact_id,
+            'contribution_type' => 'Cash',
+            'currency' => 'USD',
+            'payment_instrument' => 'Credit Card',
+            'total_amount' => $amount,
+            'trxn_id' => 'TEST_GATEWAY ' . mt_rand(),
+            'source' => 'EUR 2020',
+        ) );
+
+        $this->assertEquals( 1, TestMailer::countMailings() );
+
+        $mailing = TestMailer::getMailing( 0 );
+        $this->assertEquals( 1, preg_match( "/{$amount}/", $mailing['html'] ),
+            'Found amount in the notification email body.' );
+    }
+}
diff --git 
a/sites/all/modules/wmf_campaigns/templates/html/notification.en.html 
b/sites/all/modules/wmf_campaigns/templates/html/notification.en.html
new file mode 100644
index 0000000..59b1adb
--- /dev/null
+++ b/sites/all/modules/wmf_campaigns/templates/html/notification.en.html
@@ -0,0 +1 @@
+<p>Contribution for campaign {{ campaignKey }}: Contact ID {{ 
contribution.contact_id }}, [link to <a href="{{ civiUrl|raw }}">Civi 
console</a>]</p>
diff --git a/sites/all/modules/wmf_campaigns/tests/WmfCampaignTest.php 
b/sites/all/modules/wmf_campaigns/tests/WmfCampaignTest.php
new file mode 100644
index 0000000..3a9a5ba
--- /dev/null
+++ b/sites/all/modules/wmf_campaigns/tests/WmfCampaignTest.php
@@ -0,0 +1,76 @@
+<?php
+
+use wmf_communication\TestMailer;
+
+class WmfCampaignTest extends BaseWmfDrupalPhpUnitTestCase {
+    function setUp() {
+        parent::setUp();
+        civicrm_initialize();
+
+        TestMailer::setup();
+
+        $this->campaign_custom_field_name = wmf_civicrm_get_custom_field_name( 
'Appeal' );
+
+        $this->campaign_key = 'fooCamp' . mt_rand();
+        $this->notification_email = '[email protected]';
+
+        $result = civicrm_api3( 'Contact', 'create', array(
+            'contact_type' => 'Individual',
+            'first_name' => 'Testes',
+        ) );
+        $this->contact_id = $result['id'];
+
+        db_merge( 'wmf_campaigns_campaign' )
+            ->key( array( 'campaign_key' => $this->campaign_key ) )
+            ->fields( array(
+                'campaign_key' => $this->campaign_key,
+                'notification_email' => $this->notification_email,
+            ) )
+            ->execute();
+    }
+
+    function testMatchingDonation() {
+        $result = civicrm_api3( 'Contribution', 'create', array(
+            'contact_id' => $this->contact_id,
+            'contribution_type' => 'Cash',
+            'currency' => 'USD',
+            'payment_instrument' => 'Credit Card',
+            'total_amount' => '1.23',
+            'trxn_id' => 'TEST_GATEWAY ' . mt_rand(),
+            $this->campaign_custom_field_name => $this->campaign_key,
+        ) );
+
+        $this->assertEquals( 1, TestMailer::countMailings() );
+
+        $mailing = TestMailer::getMailing( 0 );
+        $this->assertNotEquals( false, strpos( $mailing['html'], 
$this->campaign_key ),
+            'Campaign name found in notification email.' );
+    }
+
+    function testNonMatchingDonation() {
+        $result = civicrm_api3( 'Contribution', 'create', array(
+            'contact_id' => $this->contact_id,
+            'contribution_type' => 'Cash',
+            'currency' => 'USD',
+            'payment_instrument' => 'Credit Card',
+            'total_amount' => '1.23',
+            'trxn_id' => 'TEST_GATEWAY ' . mt_rand(),
+            $this->campaign_custom_field_name => $this->campaign_key . "NOT",
+        ) );
+
+        $this->assertEquals( 0, TestMailer::countMailings() );
+    }
+
+    function testNoCampaignDonation() {
+        $result = civicrm_api3( 'Contribution', 'create', array(
+            'contact_id' => $this->contact_id,
+            'contribution_type' => 'Cash',
+            'currency' => 'USD',
+            'payment_instrument' => 'Credit Card',
+            'total_amount' => '1.23',
+            'trxn_id' => 'TEST_GATEWAY ' . mt_rand(),
+        ) );
+
+        $this->assertEquals( 0, TestMailer::countMailings() );
+    }
+}
diff --git a/sites/all/modules/wmf_campaigns/wmf_campaigns.module 
b/sites/all/modules/wmf_campaigns/wmf_campaigns.module
index da49797..67f87f0 100644
--- a/sites/all/modules/wmf_campaigns/wmf_campaigns.module
+++ b/sites/all/modules/wmf_campaigns/wmf_campaigns.module
@@ -1,6 +1,7 @@
 <?php
 
 use wmf_communication\Mailer;
+use wmf_communication\Templating;
 
 const WMF_CAMPAIGNS_OPTION_GROUP_NAME = 'appeal_20080709183729';
 
@@ -199,57 +200,76 @@
 }
 
 /**
- * implementation of hook_queue2civicrm_import
+ * Implements hook_civicrm_custom
  */
-function wmf_campaigns_queue2civicrm_import( $contributionInfo ) {
-    if ( empty( $contributionInfo['msg']['utm_campaign'] ) ) {
-        watchdog( 'wmf_campaigns', "No campaign for message", NULL, 
WATCHDOG_INFO );
-        return;
-    }
+function wmf_campaigns_civicrm_custom( $action, $groupId, $entityId, $params ) 
{
+    switch ( $action ) {
+    case 'create':
+        $result = civicrm_api3( 'CustomGroup', 'get', array(
+            'name' => 'Gift_Data',
+        ) );
+        $giftDataGroupId = (int)$result['id'];
 
-    $campaignKey = $contributionInfo['msg']['utm_campaign'];
-    $campaign = WmfCampaign::fromKey( $campaignKey );
-    if ( !$campaign || !$campaign->getNotificationEmail() ) {
-        watchdog( 'wmf_campaigns', "No special behaviors configured for 
campaign {$campaignKey}", NULL, WATCHDOG_INFO );
-        return;
-    }
+        if ( (int)$groupId === $giftDataGroupId ) {
+            foreach ( $params as $index => $values ) {
+                if ( $values['column_name'] === 'appeal' ) {
+                    $contributionId = $values['entity_id'];
+                    $campaignKey = $values['value'];
+                    break;
+                }
+            }
 
-    $email = $campaign->getNotificationEmail();
-    watchdog( 'wmf_campaigns', "Notifying {$email} about match on campaign 
{$campaignKey}", NULL, WATCHDOG_INFO );
+            if ( !$campaignKey ) {
+                watchdog( 'wmf_campaigns', "No campaign for message", NULL, 
WATCHDOG_INFO );
+                return;
+            }
 
-    //TODO: template this POS. So inconvenient.
-    $letter = array(
-        'from_address' => "[email protected]",
-        'from_name' => "Campaign notifer",
-        'reply_to' => "[email protected]",
-        'subject' => "Campaign donation: {$campaignKey}",
-    );
-    $civiUrl = CRM_Utils_System::url( 'civicrm/contact/view/contribution',
-        array(
-            'reset' => 1,
-            'id' => $contributionInfo['contribution_id'],
-            'cid' => $contributionInfo['contact_id'],
-            'action' => 'view',
-        ),
-        true // absolute link
-    );
-    $letter['html'] = <<<EOS
-<p>Contribution for campaign {$campaignKey}: Contact ID 
{$contributionInfo['contact_id']}, [link to <a href="{$civiUrl}">Civi 
console</a>]</p>
-EOS;
+            $campaign = WmfCampaign::fromKey( $campaignKey );
+            if ( !$campaign || !$campaign->getNotificationEmail() ) {
+                watchdog( 'wmf_campaigns', "No special behaviors configured 
for campaign {$campaignKey}", NULL, WATCHDOG_INFO );
+                return;
+            }
 
-    $civiUrl = html_entity_decode( $civiUrl );
-    $letter['plaintext'] = <<<EOS
-Contribution for campaign {$campaignKey}: Contact ID 
{$contributionInfo['contact_id']}
+            $result = civicrm_api3( 'Contribution', 'get', array(
+                'id' => $contributionId,
+            ) );
+            $contribution = array_pop( $result['values'] );
 
-{$civiUrl}
-EOS;
+            $email = $campaign->getNotificationEmail();
+            watchdog( 'wmf_campaigns', "Notifying {$email} about match on 
campaign {$campaignKey}", NULL, WATCHDOG_INFO );
 
-    $addressees = explode( ",", $campaign->getNotificationEmail() );
-    $mailer = Mailer::getDefault();
-    foreach ( $addressees as $recipient ) {
-        $letter['to_address'] = trim( $recipient );
-        $letter['to_name'] = t( "Dear donor services" );
+            //TODO: addresses should come from GUI config.
+            $letter = array(
+                'from_address' => "[email protected]",
+                'from_name' => "Campaign notifer",
+                'reply_to' => "[email protected]",
+                'subject' => "Campaign donation: {$campaignKey}",
+            );
+            $civiUrl = CRM_Utils_System::url( 
'civicrm/contact/view/contribution',
+                array(
+                    'reset' => 1,
+                    'id' => $contribution['id'],
+                    'cid' => $contribution['contact_id'],
+                    'action' => 'view',
+                ),
+                true // absolute link
+            );
+            $params = array(
+                'civiUrl' => $civiUrl,
+                'campaignKey' => $campaignKey,
+                'contribution' => $contribution,
+            );
+            $template = new Templating( __DIR__ . '/templates', 
'notification', 'en', $params, 'html' );
+            $letter['html'] = $template->render();
 
-        $mailer->send( $letter );
+            $addressees = explode( ",", $campaign->getNotificationEmail() );
+            $mailer = Mailer::getDefault();
+            foreach ( $addressees as $recipient ) {
+                $letter['to_address'] = trim( $recipient );
+                $letter['to_name'] = t( "Dear donor services" );
+
+                $mailer->send( $letter );
+            }
+        }
     }
 }
diff --git a/sites/all/modules/wmf_communication/tests/TestMailer.php 
b/sites/all/modules/wmf_communication/tests/TestMailer.php
index f1fe85c..88ee76d 100644
--- a/sites/all/modules/wmf_communication/tests/TestMailer.php
+++ b/sites/all/modules/wmf_communication/tests/TestMailer.php
@@ -2,10 +2,12 @@
 namespace wmf_communication;
 
 class TestMailer implements IMailer {
-    static private $mailings = array();
+    static protected $mailings;
 
     public function setup() {
         Mailer::$defaultSystem = 'test';
+
+        self::$mailings = array();
     }
 
     public function send( $email ) {
@@ -17,6 +19,6 @@
     }
 
     public function getMailing( $index ) {
-        return $mailings[$index];
+        return self::$mailings[$index];
     }
 }

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

Gerrit-MessageType: merged
Gerrit-Change-Id: Iad4da4aab1cbca206b3a66b11023e928f0b4312e
Gerrit-PatchSet: 15
Gerrit-Project: wikimedia/fundraising/crm
Gerrit-Branch: master
Gerrit-Owner: Awight <[email protected]>
Gerrit-Reviewer: Ejegg <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

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

Reply via email to