Jump to content

Extension:DonationInterface

From mediawiki.org
MediaWiki extensions manual
DonationInterface
Release status: stable
Implementation Special page
Description Provides fundraising mechanisms for collecting payments
Author(s) Elliott Eggleston, Maggie Epps, Dylan Kozlowski. inactive: Casey Dentinger, Katie Horn, Adam Roses Wight, Matt Walker, Ryan Kaldari, Sherah Smith
Latest version 2.1.0
Compatibility policy Master maintains backward compatibility.
MediaWiki >= 1.39
Composer wikimedia/donation-interface
License GNU General Public License 2.0 or later
Download
  • $wgDonationInterfaceMinFraudAlarmLimit
  • $wgDonationInterfaceEmployersListDataFileLocation
  • $wgDonationInterfaceEnableMinFraud
  • $wgDonationInterfaceEnableIPVelocityFilter
  • $wgPaypalExpressGatewayTestingCertificateURL
  • $wgDonationInterfaceSessionVelocity_HitScore
  • $wgDonationInterfaceChooserProblemURL
  • $wgDonationInterfaceVariantConfigurationDirectory
  • $wgDonationInterfaceDefaultAppeal
  • $wgDonationInterfaceFallbackCurrencyByCountry
  • $wgDonationInterfaceCurlVerboseLog
  • $wgDonationInterfaceIPDenyFailScore
  • $wgDonationInterfaceTest
  • $wgDonationInterfaceLogClientErrors
  • $wgDonationInterfaceTaxDedCountries
  • $wgDonationInterfaceSalt
  • $wgDonationInterfaceClientErrorLogIgnorePatterns
  • $wgDonationInterfaceMajorGiftsEmail
  • $wgPaypalExpressGatewayTestingSignatureURL
  • $wgDonationInterfaceIPVelocityFailScore
  • $wgDonationInterfaceEnableGatewayChooser
  • $wgDonationInterfaceMonthlyConvertCountries
  • $wgDonationInterfaceCustomFiltersRiskScore
  • $wgDonationInterfaceMinFraudLicenseKey
  • $wgDonationInterfaceEnableBannerHistoryLog
  • $wgDonationInterfaceSurnameFirstCountries
  • $wgAmazonGatewayLoginScript
  • $wgDonationInterfaceMinFraudWeight
  • $wgGravyGatewayEnabled
  • $wgDonationInterfaceMinFraudAccountId
  • $wgDonationInterfaceUseSyslog
  • $wgDonationInterfaceHeader
  • $wgDonationInterfaceDisplayDebug
  • $wgDonationInterfaceFundraiserMaintenance
  • $wgDonationInterfaceEmailFormHelpEmail
  • $wgDonationInterfaceRecurringUpgradeMaxUSD
  • $wgDonationInterfaceRecurringUpgradeOptions
  • $wgDonationInterfaceEmailPreferencesCountries
  • $wgDonationInterfaceCancelPage
  • $wgDonationInterfaceEnableFunctionsFilter
  • $wgDonationInterfaceNotifyOnConvert
  • $wgDonationInterfaceEmailPreferencesSnoozeDays
  • $wgDonationInterfaceAppealWikiTemplate
  • $wgIngenicoGatewayEnabled
  • $wgDonationInterfaceEmailPreferencesLanguages
  • $wgDonationInterfaceCiviproxyURLBase
  • $wgDonationInterfaceSaveCommStats
  • $wgDonationInterfaceMonthlyConvertAmounts
  • $wgDonationInterfaceMonthlyConvertDefaultModule
  • $wgBraintreeGatewayEnabled
  • $wgDonationInterfaceLocalConfigurationDirectory
  • $wgDonationInterfaceCustomFiltersRefRules
  • $wgDonationInterfaceGatewayAdapters
  • $wgDonationInterfaceGeoIpDbPath
  • $wgDonationInterfaceEnableSystemStatus
  • $wgDonationInterfaceEnableSessionVelocityFilter
  • $wgDonationInterfaceSendOptInOnFailure
  • $wgDonationInterfaceEmailDomainMap
  • $wgDonationInterfaceEnableSourceFilter
  • $wgDonationInterfaceIPVelocityThreshhold
  • $wgDonationInterfaceRecurringDonateURL
  • $wgDonationInterfaceEnableReferrerFilter
  • $wgDonationInterfaceSessionVelocity_Multiplier
  • $wgDonationInterfaceForbiddenCountries
  • $wgAmazonGatewayEnabled
  • $wgDonationInterfaceIPVelocityTimeout
  • $wgDonationInterfaceTaxURL
  • $wgDonationInterfaceEnableCustomFilters
  • $wgDonationInterfaceProblemsURL
  • $wgPaypalExpressGatewayCertificateURL
  • $wgDonationInterfaceUtmMediumMap
  • $wgDonationInterfaceTimeout
  • $wgPaypalExpressGatewayEnabled
  • $wgAdyenCheckoutGatewayEnabled
  • $wgDonationInterface3DSRules
  • $wgDonationInterfaceNameFilterRules
  • $wgDonationInterfaceDefaultEmail
  • $wgDonationInterfaceMinFraudErrorScore
  • $wgDonationInterfaceUtmSourceMap
  • $wgDonationInterfaceRetryLoopCount
  • $wgDonationInterfaceUtmCampaignMap
  • $wgDonationInterfaceLogoOverride
  • $wgDonationInterfaceCountryMap
  • $wgDonationInterfaceSessionVelocity_Threshold
  • $wgDonationInterfaceMessageSourceType
  • $wgDonationInterfaceSessionVelocity_DecayRate
  • $wgDonationInterfaceFallbackCurrency
  • $wgDonationInterfacePolicyURL
  • $wgDonationInterfaceCustomFiltersInitialFunctions
  • $wgDonationInterfaceCustomFiltersFunctions
  • $wgDonationInterfaceCustomFiltersActionRanges
  • $wgDonationInterfaceOtherWaysURL
  • $wgDonationInterfaceMinFraudExtraFields
  • $wgDonationInterfaceMinFraudClientOptions
  • $wgDonationInterfaceLogCompleted
  • $wgDonationInterfaceCustomFiltersSrcRules
  • $wgPaypalExpressGatewaySignatureURL
  • $wgDlocalGatewayEnabled
  • $wgDonationInterfaceFailPage
  • $wgDonationInterfaceGatewayPriorityRules
  • $wgDonationInterfaceEnableConversionLog
  • $wgDonationInterfaceThankYouPage
  • $wgDonationInterfaceProblemsEmail
  • $wgIngenicoGatewayHostedFormVariants
  • $wgDonationInterfaceNoScriptRedirect
  • $wgDonationInterfaceFaqURL
  • $wgDonationInterfaceDebugLog
Quarterly downloads 3 (Ranked 130th)
Translate the DonationInterface extension if it is available at translatewiki.net
Issues Open tasks · Report a bug

DonationInterface renders payment forms and provides fundraising mechanisms for collecting and tracking payments through various payment gateways.

Overview

The majority of the work done by the Donation Interface extension is in communicating with payment gateways. We also provide a user-facing forms layer for accepting donations.

Installation

Configuration

Include the following line in LocalSettings.php:

wfLoadExtension( "DonationInterface" );

Next, define which gateways you want to be enabled.

For example, the following would turn on all current gateways and extensions (TODO: Document defaults and update.):

$wgDonationInterfaceAdyenGatewayEnabled = true;
$wgDonationInterfaceAmazonGatewayEnabled = true;
$wgDonationInterfaceAstroPayGatewayEnabled = true;
$wgDonationInterfaceGlobalCollectGatewayEnabled = true;
$wgDonationInterfaceIngenicoGatewayEnabled = true;
$wgDonationInterfaceEnableMinFraud = true;
$wgDonationInterfaceEnableReferrerFilter = true;
$wgDonationInterfaceEnableSourceFilter = true;

After this, TODO be sure to define account information for each gateway you intend to use, for example:

    <?php
    # settings.d/wikis/paymentswiki/settings.d/01-DI-real.php

    $wgGlobalCollectGatewayAccountInfo = array(
        'default' => array(
            'MerchantID' => '1234',
        ),
    );

    $wgPaypalGatewayAccountInfo = array(
        'default' => array(
            'AccountEmail' => 'magoo@localhost.net',
        ),
    );

Important Note:

DonationInterface searches for globals in a special way.

Any DonationInterface global used by a gateway, can be assigned a value that is either specific to that gateway, or the default for the entire extension (with the specifics overriding the default where both are present).

To assign an extension-wide default for gateway globals, simply swap out the gateway prefix in the global variable name, to "wgDonationInterface".

For instance: To turn on syslogging by default for the entire DonationInterface extension instead of just, say, the payflow pro gateway, change this:

$wgIngenicoGatewayUseSyslog = true;

to this:

$wgDonationInterfaceUseSyslog = true;

Syslog will now be enabled for all gateways, unless you turn them off with gateway-specific globals.

Additional configuration

To create custom donation filtering rules, set the $wgCustomFiltersRefRules and $wgCustomFiltersSrcRules global variables in your LocalSettings.php file.

These should be set to associative arrays which pair regex patterns with risk score numbers, for example:

// Filter for suspicious HTTP referrer URLs
$wgCustomFiltersRefRules = array(
    '/hackers\.com/' => 100
    '/wikipedia\.org/' => -50,
);
// Filter for suspicious utm_source values
$wgCustomFiltersSrcRules = array(
    '/TestNotice1/' => 50
    '/foobar/' => -100,
);

Define Globals in LocalSettings.php

While there are many more globals available to override, the following probably need to be defined in LocalSettings if you want DonationInterface to actually work.

Global variables are defined in DonationInterface.php.

TODO: update

Global Name Purpose Type
$wgGlobalCollectGatewayMerchantID Our Merchant ID with GlobalCollect string
$wgDonationInterfaceAllowedHtmlForms A global whitelist of forms allowed to be loaded via RapidHtml. Intended to be used by any gateway. NOTE: This is not actually used anywhere directly. You must add these values to a gateway's AllowedHtmlForms for them to actually get used on any given gateway. Array. For each form, the key should be the name of the form (aka "ffname"), and the value should be the file's location.
$wgGlobalCollectGatewayAllowedHtmlForms The definitive whitelist of forms allowed to be loaded via RapidHtml, for GlobalCollect. Array. For each form, the key should be the name of the form (aka "ffname"), and the value should be the file's location. NOTE: If you wish to use the global list of forms as well, you will have to set $wgGlobalCollectGatewayAllowedHtmlForms = $wgDonationInterfaceAllowedHtmlForms manually, before adding (or removing) forms locally.
$wgDonationInterfaceDisplayDebug Set to true to get extra debugging information dumped to the screen. boolean

Implementation

The Code

Very generally speaking, the process of completing a donation goes like this:

  • The donor is sent to a donation form that is already tied to a specific payment gateway. This form will be controlled by a gateway-specific unlisted special page of a class descended from the GatewayForm class.
  • The extended GatewayForm class will instantiate its gateway adapter. On construction, the gateway adapter will gather, normalize, and validate any relevant data in $wgRequest. All gateways use the same class, DonationData, to accomplish this task. Doing this means that all the data is subject to the same normalization and validation processes, no matter who's asking for it or where it came from.
  • The controlling GatewayForm child class will then use the gateway adapter to determine where the user is in the donation process, and if appropriate (no errors on validation, all data present, no strangeness with the edit token or session, that sort of thing), use that same gateway adapter to interact with the remote payment servers in order to take the next step in the donation process. As every payment gateway has its own set of rules (and in some cases, completely different transaction types that are not directly analogous to anything else in any of the other gateways) it is up to the adapter to sort all of that out internally, and only expose functionality to the controlling object in such a way that it seems more or less universal across all possible adapter objects.
  • After having the gateway adapter perform one or more transactions with the remote payment gateway, the controlling object would then use the gateway to determine what happened, and display appropriate results to the prospective donor. This could be a "Thank you" page, an error displayed on the submitted form prompting the user to try again in a meaningful way, or a more fatal sort of error page.

GatewayAdapter class

(DonationInterface/gateway_common/gateway.adapter.php) - This is an abstract class that takes care of everything a general gateway needs to do. It it also supposed to yell at you rather loudly if you fail to define any of the particulars that a gateway needs, in order to be able to do anything worthwhile.

GatewayForm

(DonationInterface/gateway_common/GatewayForm.php) - A class that extends UnlistedSpecialPage. This will take care of all the not-gateway-specific functionality necessary to present a donation form to a user, and get the results. Of particular interest are the mechanisms for displaying the requested form (or not), handling some of the more universal aspects of form validation, and fetching data that could be used by the specified forms (as in, a list of countries and their codes for a country drop-down).

Classes that inherit from these will be specific to a particular payment gateway. As such, they will be located in a folder named something like DonationInterface/[name]_gateway/.

Most adapters will implement GatewayForm for two routes: the initial payment form, and a result switcher page.

The initial payment form is responsible for rendering a form with inputs for the mandatory data to be collected. Alternatively, some gateways such as GlobalCollect will render an iframed form hosted by the payment processor, and others such as PayPal and Amazon will transparently redirect to the processor unless the donation information (currency and amount) are invalid and must be corrected.

The result switcher is usually not responsible for confirming payment or performing further authorization, it simply routes the donor to either the Thank You or Failure pages, depending on approximate responses from the processor.

DonationData class

(DonationInterface/gateway_common/DonationData.php) - This class is intended to handle everything that we are likely to want to do with Donation Data. It should load the data in a consistent way from any appropriate source (including a test), saves relevant Contribution Tracking data, generates data we always need to generate (like order IDs), normalizes everything, and hands it back to the gateway. Classes inheriting from GatewayAdapter will instantiate a DonationData class on creation. The GatewayAdapter child classes should only ever use data that has come through the DonationData class. It also handles edit tokens.

DataValidator

All data is first normalized by DonationData, and is then validated. If data fails validation, all processing is halted and the donor is redirected back to the form where they can correct any errors. Messages are displayed to guide the user through the corrections. TODO: make messages human-readable, attach to fields rather than pop-up, etc.

The gateway adapter is consulted for some of these validations, for example a lower and upper threshold for valid donation amounts, and accepted currencies.

Constructing a Gateway Adapter

Quick picture of what happens when a Gateway Adapter is initially constructed

Defining A New Gateway Adapter

GatewayAdapter extends the GatewayType interface. TODO: Here is a quick guide to defining the functions in GatewayType.

Testing

Unit tests can be found in the tests directory of the DonationInterface extension.

To run unit tests go to the mediawiki-core directory, then under tests/phpunit:

cd /srv/org.wikimedia.payments
composer phpuninit:entrypoint -- --group DonationInterface

Development

Composer

Whenever composer.json changes, you must run composer update --no-dev to refresh the contents of vendor/ .

For WMF production, vendor is deployed on the "deployment" branch as a git submodule. You must rm -rf the package ".git" directories when committing new packages, otherwise they will be treated as misshapen, nested submodules and you don't want to go there.

Roadmap

Some things we want to do:

  • Decouple presentation layer from controllers and payments backend (Yes Done)
    • Kill RapidHTML and use a mainline templating engine (Yes Done)
    • Consolidate forms into a single universal form, with boolean params that control block visibility and available features: (Yes Done)
  • Decouple payment processing from the MediaWiki framework, so it can be used as a standalone library (In progress In progress)
    • Provide access to the payments library inside of Drupal, to enable refunds, cancellation, and status retrieval from CiviCRM (In progress In progress)
This extension is deployed on the Wikimedia Foundation's payments cluster rather than the main wiki cluster, so it does not appear in operations/mediawiki-config.