r85707 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r85706‎ | r85707 | r85708 >
Date:00:40, 9 April 2011
Author:tparscal
Status:ok (Comments)
Tags:
Comment:
Creating new extension for collecting and verifying email addresses. This code is nearly complete but totally untested.
Modified paths:
  • /trunk/extensions/EmailCapture (added) (history)
  • /trunk/extensions/EmailCapture/EmailCapture.i18n.php (added) (history)
  • /trunk/extensions/EmailCapture/EmailCapture.php (added) (history)
  • /trunk/extensions/EmailCapture/EmailCaptureHooks.php (added) (history)
  • /trunk/extensions/EmailCapture/SpecialEmailCapture.php (added) (history)
  • /trunk/extensions/EmailCapture/api (added) (history)
  • /trunk/extensions/EmailCapture/api/ApiEmailCapture.php (added) (history)
  • /trunk/extensions/EmailCapture/sql (added) (history)
  • /trunk/extensions/EmailCapture/sql/CreateEmailCaptureTable.sql (added) (history)

Diff [purge]

Index: trunk/extensions/EmailCapture/EmailCapture.i18n.php
@@ -0,0 +1,27 @@
 2+<?php
 3+/**
 4+ * Internationalisation for EmailCapture extension
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+$messages = array();
 11+
 12+/** English
 13+ * @author Trevor Parscal
 14+ */
 15+$messages['en'] = array(
 16+ 'emailcapture' => 'Email Capture',
 17+ 'emailcapture-desc' => 'Capture email addresses, and allow users to verify them through email',
 18+ 'emailcapture-response-subject' => '{{SITENAME}} Email Verification',
 19+ 'emailcapture-response-body' => 'To verify your email address, following this link:
 20+ $1
 21+
 22+You can also visit:
 23+ $2
 24+and enter the following verification code:
 25+ $3
 26+
 27+Thank you for verifying your email address.',
 28+);
Index: trunk/extensions/EmailCapture/sql/CreateEmailCaptureTable.sql
@@ -0,0 +1,13 @@
 2+-- Captured email addresses
 3+CREATE TABLE IF NOT EXISTS /*_*/email_capture (
 4+ -- Email address
 5+ ec_email tinytext NOT NULL,
 6+ -- Additional information
 7+ ec_info blob NOT NULL,
 8+ -- Verification code
 9+ ec_code varbinary(32) NOT NULL DEFAULT '',
 10+ -- Verified
 11+ ec_verified boolean DEFAULT 0
 12+) /*$wgDBTableOptions*/;
 13+CREATE UNIQUE INDEX /*i*/ac_email_key ON /*_*/email_capture (ec_email);
 14+CREATE INDEX /*i*/ac_code_verified_key ON /*_*/email_capture (ec_code, ec_verified);
Index: trunk/extensions/EmailCapture/EmailCapture.php
@@ -0,0 +1,45 @@
 2+<?php
 3+/**
 4+ * EmailCapture extension
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ *
 9+ * @author Trevor Parscal <trevor@wikimedia.org>
 10+ * @license GPL v2 or later
 11+ * @version 0.3.0
 12+ */
 13+
 14+/* Configuration */
 15+
 16+$wgEmailCaptureSendAutoResponse = true;
 17+$wgEmailCaptureAutoResponse = array(
 18+ 'from' => $wgPasswordSender,
 19+ 'subject-msg' => 'emailcapture-response-subject',
 20+ 'body-msg' => 'emailcapture-response-body',
 21+ 'reply-to' => null,
 22+ 'content-type' => null,
 23+);
 24+
 25+/* Setup */
 26+
 27+$wgExtensionCredits['other'][] = array(
 28+ 'path' => __FILE__,
 29+ 'name' => 'EmailCapture',
 30+ 'author' => array( 'Trevor Parscal' ),
 31+ 'version' => '0.3.0',
 32+ 'url' => 'http://www.mediawiki.org/wiki/Extension:EmailCapture',
 33+ 'descriptionmsg' => 'emailcapture-desc',
 34+);
 35+$dir = dirname( __FILE__ ) . '/';
 36+$wgExtensionMessagesFiles['EmailCapture'] = $dir . 'EmailCapture.i18n.php';
 37+// API
 38+$wgAutoloadClasses['ApiEmailCapture'] = $dir . 'api/ApiEmailCapture.php';
 39+$wgAPIModules['emailcapture'] = 'ApiEmailCapture';
 40+// Schema
 41+$wgAutoloadClasses['EmailCaptureHooks'] = $dir . 'EmailCaptureHooks.php';
 42+$wgHooks['LoadExtensionSchemaUpdates'][] = 'EmailCaptureHooks::loadExtensionSchemaUpdates';
 43+$wgHooks['ParserTestTables'][] = 'EmailCaptureHooks::parserTestTables';
 44+// SpecialPage
 45+$wgAutoloadClasses['SpecialEmailCapture'] = $dir . "SpecialEmailCapture.php";
 46+$wgSpecialPages['EmailCapture'] = 'SpecialEmailCapture';
Index: trunk/extensions/EmailCapture/SpecialEmailCapture.php
@@ -0,0 +1,25 @@
 2+<?php
 3+class SpecialEmailCapture extends SpecialPage {
 4+
 5+ function __construct() {
 6+ parent::__construct( 'EmailCapture', 'emailcapture' );
 7+ }
 8+
 9+ function execute( $par ) {
 10+ global $wgOut, $wgRequest;
 11+
 12+ $this->setHeaders();
 13+
 14+ $code = $wgRequest->getVal( 'verify' );
 15+ if ( $verify !== null ) {
 16+ // $affectedRows = ( UPDATE email_capture SET (ec_veified = 1) WHERE ec_code = $code )
 17+ // if ( $affectedRows ) {
 18+ // show success
 19+ // } else {
 20+ // show failure
 21+ // }
 22+ // exit
 23+ }
 24+ // Show simple form for submitting verification code
 25+ }
 26+}
Index: trunk/extensions/EmailCapture/EmailCaptureHooks.php
@@ -0,0 +1,41 @@
 2+<?php
 3+/**
 4+ * Hooks for EmailCapture extension
 5+ *
 6+ * @author tparscal
 7+ */
 8+class EmailCaptureHooks {
 9+ /**
 10+ * LoadExtensionSchemaUpdates hook
 11+ */
 12+ public static function loadExtensionSchemaUpdates( $updater = null ) {
 13+ if ( $updater === null ) {
 14+ global $wgExtNewTables;
 15+ $wgExtNewTables[] = array(
 16+ 'email_capture',
 17+ dirname( __FILE__ ) . '/sql/CreateEmailCaptureTable.sql'
 18+ );
 19+ } else {
 20+ $dir = dirname( __FILE__ );
 21+ $db = $updater->getDB();
 22+ if ( !$db->tableExists( 'article_feedback' ) ) {
 23+ // Initial install tables
 24+ $updater->addExtensionUpdate( array(
 25+ 'addTable',
 26+ 'email_capture',
 27+ $dir . '/sql/CreateEmailCaptureTable.sql',
 28+ true
 29+ ) );
 30+ }
 31+ }
 32+ return true;
 33+ }
 34+
 35+ /**
 36+ * ParserTestTables hook
 37+ */
 38+ public static function parserTestTables( &$tables ) {
 39+ $tables[] = 'email_capture';
 40+ return true;
 41+ }
 42+}
Index: trunk/extensions/EmailCapture/api/ApiEmailCapture.php
@@ -0,0 +1,109 @@
 2+<?php
 3+class ApiEmailCapture extends ApiBase {
 4+ public function __construct( $query, $moduleName ) {
 5+ parent::__construct( $query, $moduleName, '' );
 6+ }
 7+
 8+ public function execute() {
 9+ $params = $this->extractRequestParams();
 10+
 11+ // Validation
 12+ if ( !isset( $params['email'] ) ) {
 13+ $this->dieUsageMsg( array( 'missingparam', 'email' ) );
 14+ } else if ( !User:isValidEmailAddr( $params['email'] ) ) {
 15+ $this->dieUsage( 'The email address does not appear to be valid', 'invalidemail' );
 16+ }
 17+
 18+ // Verification code
 19+ $code = md5( 'EmailCapture' . time() . $params['email'] . $params['info'] )
 20+
 21+ // Insert
 22+ $dbw = wfGetDB( DB_MASTER );
 23+ $affectedRows = $dbw->insert(
 24+ 'email_capture',
 25+ array(
 26+ 'ec_email' => $params['email'],
 27+ 'ec_info' => isset( $params['info'] ) ? $params['email'] : null,
 28+ 'ec_code' => $code,
 29+ )
 30+ );
 31+
 32+ // Send auto-response
 33+ global $wgUser, $wgEmailCaptureSendAutoResponse, $wgEmailCaptureAutoResponse;
 34+ $link = $wgUser->getSkin()->link( 'Special:EmailCapture' );
 35+ $fullLink = $wgUser->getSkin()->link(
 36+ 'Special:EmailCapture', null, array(), array( 'verify' => $code )
 37+ );
 38+ if ( $wgEmailCaptureSendAutoResponse ) {
 39+ UserMailer::send(
 40+ $params['email'],
 41+ $wgEmailCaptureAutoResponse['from'],
 42+ wfMsg( $wgEmailCaptureAutoResponse['subject-msg'] ),
 43+ wfMsg( $wgEmailCaptureAutoResponse['body-msg'], $link, $code, $fullLink ),
 44+ $wgEmailCaptureAutoResponse['reply-to'],
 45+ $wgEmailCaptureAutoResponse['content-type'],
 46+ );
 47+ }
 48+
 49+ // Result
 50+ if ( $affectedRows === 0 ) {
 51+ $r = array( 'result' => 'Failure', 'message' => 'Duplicate email address' );
 52+ } else {
 53+ $r = array( 'result' => 'Success' );
 54+ }
 55+ $this->getResult()->addValue( null, $this->getModuleName(), $r );
 56+ }
 57+
 58+ public function getAllowedParams() {
 59+ return array(
 60+ 'email' => array(
 61+ ApiBase::PARAM_REQUIRED => true,
 62+ ApiBase::PARAM_TYPE => 'string',
 63+ ),
 64+ 'info' => array(
 65+ ApiBase::PARAM_TYPE => 'string',
 66+ ),
 67+ );
 68+ }
 69+
 70+ public function getParamDescription() {
 71+ return array(
 72+ 'email' => 'Email address to capture',
 73+ 'info' => 'Extra information to log, usually JSON encoded structured information',
 74+ );
 75+ }
 76+
 77+ public function getDescription() {
 78+ return array(
 79+ 'Capture email addresses'
 80+ );
 81+ }
 82+
 83+ public function mustBePosted() {
 84+ return true;
 85+ }
 86+
 87+ public function isWriteMode() {
 88+ return true;
 89+ }
 90+
 91+ public function getPossibleErrors() {
 92+ return array_merge( parent::getPossibleErrors(), array(
 93+ array( 'missingparam', 'email' ),
 94+ array(
 95+ 'code' => 'invalidemail',
 96+ 'info' => 'The email address does not appear to be valid'
 97+ ),
 98+ ) );
 99+ }
 100+
 101+ protected function getExamples() {
 102+ return array(
 103+ 'api.php?action=emailcapture'
 104+ );
 105+ }
 106+
 107+ public function getVersion() {
 108+ return __CLASS__ . ': $Id: ApiEmailCapture.php 85276 2011-04-03 20:32:25Z reedy $';
 109+ }
 110+}

Follow-up revisions

RevisionCommit summaryAuthorDate
r85709Followup r85707...reedy01:20, 9 April 2011
r85725EmailCapture:...ashley15:28, 9 April 2011
r85802Removed redundant missing param error information and fixes the mess that was...tparscal17:02, 11 April 2011

Comments

#Comment by Reedy (talk | contribs)   01:31, 9 April 2011

Think you need to check your autoprops are set :) Subversion/auto-props

#Comment by Trevor Parscal (WMF) (talk | contribs)   16:51, 11 April 2011

Thanks for the follow up - i set my autoprops now, forgot to do that when I reinstalled my machine's OS.

#Comment by Reedy (talk | contribs)   16:51, 11 April 2011
D
#Comment by Reedy (talk | contribs)   13:07, 9 April 2011
+			if ( !$db->tableExists( 'article_feedback' ) ) {

Looks obviously wrong

If you're offloading to 1.17 and above (don't need < 1.17 back compat), you can enforce the requiredness of the email onto the API...

#Comment by Reedy (talk | contribs)   16:52, 11 April 2011

r85725 fixes some of the other issues (by ashley)

#Comment by 😂 (talk | contribs)   14:38, 21 April 2011

It's completely wrong either way, just add the extension update unconditionally. The updater is smart enough to discard table creations when the table already exists, don't try to do it for it.

Status & tagging log