r51638 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r51637‎ | r51638 | r51639 >
Date:12:27, 9 June 2009
Author:werdna
Status:deferred
Tags:
Comment:
Reimplemented writeMessageStateForUpdated thread:
* Improve cross-database compatibility (and code readability) by using proper generation methods.
* Basic implementation of LQT email notification.
* TODO : Implement email notification for discussions on a user's talk page.
Modified paths:
  • /trunk/extensions/LiquidThreads/LiquidThreads.php (modified) (history)
  • /trunk/extensions/LiquidThreads/Lqt.i18n.php (modified) (history)
  • /trunk/extensions/LiquidThreads/LqtFunctions.php (modified) (history)
  • /trunk/extensions/LiquidThreads/classes/LqtNewMessages.php (modified) (history)
  • /trunk/extensions/LiquidThreads/classes/LqtThread.php (modified) (history)
  • /trunk/extensions/LiquidThreads/classes/LqtThreads.php (modified) (history)
  • /trunk/extensions/LiquidThreads/classes/LqtView.php (modified) (history)

Diff [purge]

Index: trunk/extensions/LiquidThreads/LqtFunctions.php
@@ -102,3 +102,15 @@
103103 return wfMsgExt( 'lqt-log-action-move', 'parseinline',
104104 array( $title->getPrefixedText(), $parameters[0], $parameters[1] ) );
105105 }
 106+
 107+function lqtGetPreferences( $user, &$preferences ) {
 108+ wfLoadExtensionMessages( 'LiquidThreads' );
 109+ $preferences['lqtnotifytalk'] =
 110+ array(
 111+ 'type' => 'toggle',
 112+ 'label-message' => 'lqt-preference-notify-talk',
 113+ 'section' => 'personal/email'
 114+ );
 115+
 116+ return true;
 117+}
Index: trunk/extensions/LiquidThreads/LiquidThreads.php
@@ -49,6 +49,7 @@
5050 $wgHooks['OldChangesListRecentChangesLine'][] = 'LqtDispatch::customizeOldChangesList';
5151 $wgHooks['SkinTemplateOutputPageBeforeExec'][] = 'LqtDispatch::setNewtalkHTML';
5252 $wgHooks['TitleGetRestrictions'][] = 'Thread::getRestrictionsForTitle';
 53+$wgHooks['GetPreferences'][] = 'lqtGetPreferences';
5354
5455 // Special pages
5556 $wgSpecialPages['DeleteThread'] = 'SpecialDeleteThread';
@@ -91,6 +92,9 @@
9293 $wgLogHeaders['liquidthreads'] = 'lqt-log-header';
9394 $wgLogActionsHandlers['liquidthreads/move'] = 'lqtFormatMoveLogEntry';
9495
 96+// Preferences
 97+$wgDefaultUserOptions['lqtnotifytalk'] = true;
 98+
9599 /** CONFIGURATION SECTION */
96100
97101 /* Number of days a thread needs to have existed to be considered for summarizing and archival */
@@ -105,3 +109,6 @@
106110 /* Allows switching LiquidThreads off for regular talk pages
107111 (intended for testing and transition) */
108112 $wgLqtTalkPages = true;
 113+
 114+/* Whether or not to activate LiquidThreads email notifications */
 115+$wgLqtEnotif = true;
Index: trunk/extensions/LiquidThreads/classes/LqtThreads.php
@@ -105,7 +105,7 @@
106106
107107 self::createTalkpageIfNeeded( $article );
108108
109 - NewMessages::writeMessageStateForUpdatedThread( $newthread );
 109+ NewMessages::writeMessageStateForUpdatedThread( $newthread, $change_type, $wgUser );
110110
111111 return $newthread;
112112 }
Index: trunk/extensions/LiquidThreads/classes/LqtView.php
@@ -176,6 +176,18 @@
177177 if ( is_array( $query ) ) $query = self::queryStringFromArray( $query );
178178 return $thread->root()->getTitle()->getFullUrl( $query );
179179 }
 180+
 181+ static function permalink( $thread, $text = null, $method = null, $operand = null,
 182+ $sk = null, $attribs = array() ) {
 183+ if ( is_null($sk) ) {
 184+ global $wgUser;
 185+ $sk = $wgUser->getSkin();
 186+ }
 187+
 188+ list( $title, $query ) = self::permalinkData( $thread, $method, $operand );
 189+
 190+ return $sk->link( $title, $text, $attribs, $query );
 191+ }
180192
181193 static function permalinkUrlWithDiff( $thread ) {
182194 $changed_thread = $thread->changeObject();
Index: trunk/extensions/LiquidThreads/classes/LqtNewMessages.php
@@ -40,40 +40,167 @@
4141 * Write a user_message_state for each user who is watching the thread.
4242 * If the thread is on a user's talkpage, set that user's newtalk.
4343 */
44 - static function writeMessageStateForUpdatedThread( $t ) {
 44+ static function writeMessageStateForUpdatedThread( $t, $type, $changeUser ) {
4545 global $wgDBprefix, $wgUser;
 46+
 47+ wfDebugLog( 'LiquidThreads', 'Doing notifications' );
4648
4749 if ( $t->article()->getTitle()->getNamespace() == NS_USER ) {
4850 $name = $t->article()->getTitle()->getDBkey();
4951 list( $name ) = split( '/', $name ); // subpages
5052 $user = User::newFromName( $name );
51 - if ( $user && $user->getID() != $wgUser->getID() ) {
 53+ if ( $user && $user->getID() != $changeUser->getID() ) {
5254 $user->setNewtalk( true );
5355 }
5456 }
5557
5658 $dbw =& wfGetDB( DB_MASTER );
5759
58 - $talkpage_t = $t->article()->getTitle();
 60+ $talkpage_t = $t->article()->getTitle()->getSubjectPage();
5961 $root_t = $t->root()->getTitle();
6062
6163 $q_talkpage_t = $dbw->addQuotes( $talkpage_t->getDBkey() );
6264 $q_root_t = $dbw->addQuotes( $root_t->getDBkey() );
6365
6466 // Select any applicable watchlist entries for the thread.
65 - $where_clause = <<<SQL
66 -(
67 - (wl_namespace = {$talkpage_t->getNamespace()} and wl_title = $q_talkpage_t )
68 -or (wl_namespace = {$root_t->getNamespace()} and wl_title = $q_root_t )
69 -)
70 -SQL;
 67+ $talkpageWhere = array( 'wl_namespace' => $talkpage_t->getNamespace(),
 68+ 'wl_title' => $talkpage_t->getDBkey() );
 69+ $rootWhere = array( 'wl_namespace' => $root_t->getNamespace(),
 70+ 'wl_title' => $root_t->getDBkey() );
 71+
 72+ $talkpageWhere = $dbw->makeList( $talkpageWhere, LIST_AND );
 73+ $rootWhere = $dbw->makeList( $rootWhere, LIST_AND );
 74+
 75+ $where_clause = $dbw->makeList( array( $talkpageWhere, $rootWhere ), LIST_OR );
7176
7277 // it sucks to not have 'on duplicate key update'. first update users who already have a ums for this thread
7378 // and who have already read it, by setting their state to unread.
74 - $dbw->query( "update {$wgDBprefix}user_message_state, {$wgDBprefix}watchlist set ums_read_timestamp = null where ums_user = wl_user and ums_thread = {$t->id()} and $where_clause" );
75 -
76 - $dbw->query( "insert ignore into {$wgDBprefix}user_message_state (ums_user, ums_thread) select user_id, {$t->id()} from {$wgDBprefix}user, {$wgDBprefix}watchlist where user_id = wl_user and $where_clause;" );
 79+
 80+ // Pull users to update the message state for, including whether or not a
 81+ // user_message_state row exists for them, and whether or not to send an email
 82+ // notification.
 83+ $dbr = wfGetDB( DB_SLAVE );
 84+ $res = $dbr->select( array( 'watchlist', 'user_message_state', 'user_properties' ),
 85+ array( 'wl_user', 'ums_user', 'ums_read_timestamp', 'up_value' ),
 86+ $where_clause, __METHOD__, array(),
 87+ array( 'user_message_state' =>
 88+ array( 'left join', array( 'ums_user=wl_user',
 89+ 'ums_thread' => $t->id() ) ),
 90+ 'user_properties' => array(
 91+ 'left join',
 92+ array( 'up_user=wl_user',
 93+ 'up_property' => 'lqtnotifytalk',
 94+ )
 95+ ),
 96+ )
 97+ );
 98+
 99+ $insert_rows = array();
 100+ $update_tuples = array();
 101+ $notify_users = array();
 102+ while( $row = $dbr->fetchObject( $res ) ) {
 103+ // Don't notify yourself
 104+ if ( $changeUser->getId() == $row->wl_user )
 105+ continue;
 106+
 107+ if ( $row->ums_read_timestamp ) {
 108+ $conds = array( 'ums_user' => $row->ums_user,
 109+ 'ums_thread' => $t->id() );
 110+ $update_tuples[$row->ums_user.$t->id()] = $dbw->makeList( $conds, LIST_AND );
 111+ } elseif ( $row->ums_user ) {
 112+ // It's already positive.
 113+ } else {
 114+ $insert_rows[] =
 115+ array(
 116+ 'ums_user' => $row->wl_user,
 117+ 'ums_thread' => $t->id(),
 118+ );
 119+ }
 120+
 121+ if ( ( is_null($row->up_value) && User::getDefaultOption( 'lqtnotifytalk' ) )
 122+ || $row->up_value ) {
 123+ $notify_users[] = $row->wl_user;
 124+ }
 125+ }
 126+
 127+ // Avoids duplicates
 128+ $update_tuples = array_values( $update_tuples );
 129+
 130+ // Do the actual updates
 131+ if ( count($insert_rows) ) {
 132+ $dbw->insert( 'user_message_state', $insert_rows, __METHOD__, array( 'IGNORE' ) );
 133+ }
 134+ if ( count($update_tuples) ) {
 135+ $where = $dbw->makeList( $update_tuples, LIST_OR );
 136+
 137+ $dbw->update( 'user_message_state', array( 'ums_read_timestamp' => null ),
 138+ array($where), __METHOD__ );
 139+ }
 140+
 141+ if ( count($notify_users) ) {
 142+ self::notifyUsersByMail( $t, $notify_users, wfTimestampNow(), $type );
 143+ }
77144 }
 145+
 146+ static function notifyUsersByMail( $t, $watching_users, $timestamp, $type ) {
 147+ wfLoadExtensionMessages( 'LiquidThreads' );
 148+ $messages = array(
 149+ Threads::CHANGE_REPLY_CREATED => 'lqt-enotif-reply',
 150+ Threads::CHANGE_NEW_THREAD => 'lqt-enotif-newthread',
 151+ );
 152+ $subjects = array(
 153+ Threads::CHANGE_REPLY_CREATED => 'lqt-enotif-subject-reply',
 154+ Threads::CHANGE_NEW_THREAD => 'lqt-enotif-subject-newthread',
 155+ );
 156+
 157+ if ( !isset($messages[$type]) || !isset($subjects[$type]) ) {
 158+ wfDebugLog( 'LiquidThreads', "Email notification failed: type $type unrecognised" );
 159+ return;
 160+ } else {
 161+ $msgName = $messages[$type];
 162+ $subjectMsg = $subjects[$type];
 163+ }
 164+
 165+ // Send email notification, fetching all the data in one go
 166+ $dbr = wfGetDB( DB_SLAVE );
 167+ $res = $dbr->select( array( 'user', 'user_properties' ), '*',
 168+ array( 'user_id' => $watching_users ), __METHOD__, array(),
 169+ array( 'user_properties' =>
 170+ array( 'left join',
 171+ array(
 172+ 'up_user=user_id',
 173+ 'up_property' => 'timecorrection'
 174+ )
 175+ )
 176+ )
 177+ );
 178+
 179+ while( $row = $dbr->fetchObject( $res ) ) {
 180+ $u = User::newFromRow( $row );
 181+
 182+ global $wgLang;
 183+
 184+ $permalink = LqtView::permalinkUrl( $t );
 185+
 186+ // Adjust with time correction
 187+ $adjustedTimestamp = $wgLang->userAdjust( $timestamp, $row->up_value );
 188+
 189+ $date = $wgLang->date( $adjustedTimestamp );
 190+ $time = $wgLang->time( $adjustedTimestamp );
 191+
 192+ $talkPage = $t->article()->getTitle()->getPrefixedText();
 193+ $msg = wfMsg( $msgName, $u->getName(), $t->subjectWithoutIncrement(),
 194+ $date, $time, $talkPage, $permalink );
 195+
 196+ global $wgPasswordSender;
 197+
 198+ $from = new MailAddress( $wgPasswordSender, 'WikiAdmin' );
 199+ $to = new MailAddress( $u );
 200+ $subject = wfMsg( $subjectMsg, $t->subjectWithoutIncrement() );
 201+
 202+ UserMailer::send( $to, $from, $subject, $msg );
 203+ }
 204+ }
78205
79206 static function newUserMessages( $user ) {
80207 global $wgDBprefix;
Index: trunk/extensions/LiquidThreads/classes/LqtThread.php
@@ -160,7 +160,7 @@
161161 __METHOD__ );
162162
163163 if ( $change_type == Threads::CHANGE_EDITED_ROOT ) {
164 - NewMessages::writeMessageStateForUpdatedThread( $this );
 164+ NewMessages::writeMessageStateForUpdatedThread( $this, $change_type, $wgUser );
165165 }
166166 }
167167
Index: trunk/extensions/LiquidThreads/Lqt.i18n.php
@@ -151,6 +151,23 @@
152152 'lqt-log-name' => 'Threaded discussion log',
153153 'lqt-log-header' => 'This log details actions taken on discussion threads.',
154154 'lqt-log-action-move' => 'moved [[$1]] from [[$2]] to [[$3]].',
 155+
 156+ // Preferences
 157+ 'lqt-preference-notify-talk' => 'Email me when somebody replies to a thread I am watching',
 158+
 159+ // Email notification
 160+ 'lqt-enotif-subject-reply' => '{{SITENAME}} discussion - Reply: $1',
 161+ 'lqt-enotif-subject-newthread' => '{{SITENAME}} discussion - New thread: $1',
 162+ 'lqt-enotif-newthread' => "Hi $1,
 163+This is a notification from {{SITENAME}} that a new thread on $5, '$2',
 164+was created on $3 at $4.
 165+
 166+You can see it at <$6>",
 167+ 'lqt-enotif-reply' => "Hi $1,
 168+This is a notification from {{SITENAME}} that a new reply to '$2' on $5,
 169+was created on $3 at $4.
 170+
 171+You can see it at <$6>",
155172 );
156173
157174 /** Message documentation (Message documentation)

Status & tagging log