Index: trunk/phase3/maintenance/archives/patch-email-notification.sql |
— | — | @@ -0,0 +1,11 @@ |
| 2 | +-- Patch for email notification on page changes T.Gries/M.Arndt 11.09.2004 |
| 3 | + |
| 4 | +-- A new column 'wl_notificationtimestamp' is added to the table 'watchlist'. |
| 5 | +-- When a page watched by a user X is changed by someone else, an email is sent to the watching user X |
| 6 | +-- if and only if the field 'wl_notificationtimestamp' is '0'. The time/date of sending the mail is then stored in that field. |
| 7 | +-- Further pages changes do not trigger new notification mails as long as user X has not re-visited that page. |
| 8 | +-- The field is reset to '0' when user X re-visits the page or when he or she resets all notification timestamps |
| 9 | +-- ("notification flags") at once by clicking the new button on his/her watchlist page. |
| 10 | +-- T. Gries/M. Arndt 11.09.2004 - December 2004 |
| 11 | + |
| 12 | +ALTER TABLE /*$wgDBprefix*/watchlist ADD (wl_notificationtimestamp varchar(14) binary NOT NULL default '0'); |
Property changes on: trunk/phase3/maintenance/archives/patch-email-notification.sql |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 13 | + native |
Added: svn:keywords |
2 | 14 | + Author Date Id Revision |
Index: trunk/phase3/maintenance/archives/patch-email-authentication.sql |
— | — | @@ -0,0 +1,3 @@ |
| 2 | +-- Patch for email authentication T.Gries/M.Arndt 27.11.2004 |
| 3 | +-- A new column is added to the table 'user'. |
| 4 | +ALTER TABLE /*$wgDBprefix*/user ADD (user_emailauthenticationtimestamp varchar(14) binary NOT NULL default '0'); |
Property changes on: trunk/phase3/maintenance/archives/patch-email-authentication.sql |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 5 | + native |
Added: svn:keywords |
2 | 6 | + Author Date Id Revision |
Index: trunk/phase3/maintenance/archives/patch-drop-user_newtalk.sql |
— | — | @@ -0,0 +1,3 @@ |
| 2 | +-- Patch for email authentication T.Gries/M.Arndt 27.11.2004 |
| 3 | +-- Table user_newtalk is dropped, as the table watchlist is now also used for storing user_talk-page notifications |
| 4 | +DROP TABLE /*$wgDBprefix*/user_newtalk; |
Property changes on: trunk/phase3/maintenance/archives/patch-drop-user_newtalk.sql |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 5 | + native |
Added: svn:keywords |
2 | 6 | + Author Date Id Revision |
Index: trunk/phase3/maintenance/updaters.inc |
— | — | @@ -146,6 +146,82 @@ |
147 | 147 | } |
148 | 148 | } |
149 | 149 | |
| 150 | +function do_watchlist_update() { |
| 151 | + global $wgDatabase; |
| 152 | + if( $wgDatabase->fieldExists( 'watchlist', 'wl_notificationtimestamp' ) ) { |
| 153 | + echo "ENOTIF: The watchlist table is already set up for email notification.\n"; |
| 154 | + } else { |
| 155 | + echo "ENOTIF: Adding wl_notificationtimestamp field for email notification management."; |
| 156 | + /* ALTER TABLE watchlist ADD (wl_notificationtimestamp varchar(14) binary NOT NULL default '0'); */ |
| 157 | + dbsource( "maintenance/archives/patch-email-notification.sql", $wgDatabase ); |
| 158 | + echo "ok\n"; |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +function do_copy_newtalk_to_watchlist() { |
| 163 | + global $wgDatabase; |
| 164 | + global $wgCommandLineMode; # this needs to be saved while getID() and getName() are called |
| 165 | + |
| 166 | + $CommandLineMode_save = $wgCommandLineMode; |
| 167 | + $wgCommandLineMode = false; # otherwise User:loadfromDatabase() early returns, but we need it herein |
| 168 | + |
| 169 | + if ( $wgDatabase->tableExists( 'user_newtalk' ) ) { |
| 170 | + $res = $wgDatabase->safeQuery( 'SELECT user_id, user_ip FROM !', |
| 171 | + $wgDatabase->tableName( 'user_newtalk' ) ); |
| 172 | + $num_newtalks=$wgDatabase->numRows($res); |
| 173 | + echo "ENOTIF: Now converting ".$num_newtalks." user_newtalk entries to watchlist table entries ... \n"; |
| 174 | + |
| 175 | + $user = new User(); |
| 176 | + for ( $i = 1; $i <= $num_newtalks; $i++ ) { |
| 177 | + $wluser = $wgDatabase->fetchObject( $res ); |
| 178 | + echo 'ENOTIF: <= user_newtalk: user_id='.$wluser->user_id.' user_ip='.$wluser->user_ip."\n"; |
| 179 | + if ($wluser->user_id == 0) { # anonymous users ... have IP numbers as "names" |
| 180 | + if ($user->isIP($wluser->user_ip)) { # do only if it really looks like an IP number (double checked) |
| 181 | + $wgDatabase->replace( 'watchlist', |
| 182 | + array(array('wl_user','wl_namespace', 'wl_title', 'wl_notificationtimestamp' )), |
| 183 | + array('wl_user' => 0, |
| 184 | + 'wl_namespace' => NS_USER_TALK, |
| 185 | + 'wl_title' => $wluser->user_ip, |
| 186 | + 'wl_notificationtimestamp' => '19700101000000' |
| 187 | + ), 'updaters.inc::do_watchlist_update2' |
| 188 | + ); |
| 189 | + echo 'ENOTIF: ====> watchlist: user_id=0 '.$wluser->user_ip."\n"; |
| 190 | + } |
| 191 | + } else { # normal users ... have user_ids |
| 192 | + $user->setID($wluser->user_id); |
| 193 | + $wgDatabase->replace( 'watchlist', |
| 194 | + array(array('wl_user','wl_namespace', 'wl_title', 'wl_notificationtimestamp' )), |
| 195 | + array('wl_user' => $user->getID(), |
| 196 | + 'wl_namespace' => NS_USER_TALK, |
| 197 | + 'wl_title' => $user->getName(), |
| 198 | + 'wl_notificationtimestamp' => '19700101000000' |
| 199 | + ), 'updaters.inc::do_watchlist_update3' |
| 200 | + ); |
| 201 | + echo 'ENOTIF: ====> watchlist: user_id='.$user->getID().' '.$user->getName()."\n"; |
| 202 | + } |
| 203 | + } |
| 204 | + echo "ENOTIF: The watchlist table has got the former user_newtalk entries.\n"; |
| 205 | + dbsource( "maintenance/archives/patch-drop-user_newtalk.sql", $wgDatabase ); |
| 206 | + echo "ENOTIF: Deleting the user_newtalk table as its entries are now in the watchlist table.\n"; |
| 207 | + } else { |
| 208 | + echo "ENOTIF: No user_newtalk table found. Nothing to convert to watchlist table entries.\n"; |
| 209 | + } |
| 210 | + $wgCommandLineMode = $CommandLineMode_save; |
| 211 | +} |
| 212 | + |
| 213 | + |
| 214 | +function do_user_update() { |
| 215 | + global $wgDatabase; |
| 216 | + if( $wgDatabase->fieldExists( 'user', 'user_emailauthenticationtimestamp' ) ) { |
| 217 | + echo "EAUTHENT: The user table is already set up for email authentication.\n"; |
| 218 | + } else { |
| 219 | + echo "EAUTHENT: Adding user_emailauthenticationtimestamp field for email authentication management."; |
| 220 | + /* ALTER TABLE user ADD (user_emailauthenticationtimestamp varchar(14) binary NOT NULL default '0'); */ |
| 221 | + dbsource( "maintenance/archives/patch-email-authentication.sql", $wgDatabase ); |
| 222 | + echo "ok\n"; |
| 223 | + } |
| 224 | +} |
| 225 | + |
150 | 226 | # Assumes that the group table has been added. |
151 | 227 | function do_group_update() { |
152 | 228 | global $wgDatabase; |
— | — | @@ -199,6 +275,9 @@ |
200 | 276 | do_linkscc_1_3_update(); flush(); |
201 | 277 | convertLinks(); flush(); |
202 | 278 | do_image_name_unique_update(); flush(); |
| 279 | + do_watchlist_update(); flush(); |
| 280 | + do_copy_newtalk_to_watchlist(); flush(); |
| 281 | + do_user_update(); flush(); |
203 | 282 | |
204 | 283 | if ( isTemplateInitialised() ) { |
205 | 284 | print "Template namespace already initialised\n"; |
Index: trunk/phase3/maintenance/tables.sql |
— | — | @@ -11,6 +11,7 @@ |
12 | 12 | user_password tinyblob NOT NULL default '', |
13 | 13 | user_newpassword tinyblob NOT NULL default '', |
14 | 14 | user_email tinytext NOT NULL default '', |
| 15 | + user_emailauthenticationtimestamp varchar(14) binary NOT NULL default '0', |
15 | 16 | user_options blob NOT NULL default '', |
16 | 17 | user_touched char(14) binary NOT NULL default '', |
17 | 18 | user_token char(32) binary NOT NULL default '', |
— | — | @@ -25,12 +26,14 @@ |
26 | 27 | UNIQUE KEY ur_user (ur_user) |
27 | 28 | ); |
28 | 29 | |
29 | | -CREATE TABLE /*$wgDBprefix*/user_newtalk ( |
30 | | - user_id int(5) NOT NULL default '0', |
31 | | - user_ip varchar(40) NOT NULL default '', |
32 | | - INDEX user_id (user_id), |
33 | | - INDEX user_ip (user_ip) |
34 | | -); |
| 30 | +-- The following table is no longer needed with Enotif >= 2.00 |
| 31 | +-- Entries for newtalk on user_talk page are handled like in the watchlist table |
| 32 | +-- CREATE TABLE /*$wgDBprefix*/user_newtalk ( |
| 33 | +-- user_id int(5) NOT NULL default '0', |
| 34 | +-- user_ip varchar(40) NOT NULL default '', |
| 35 | +-- INDEX user_id (user_id), |
| 36 | +-- INDEX user_ip (user_ip) |
| 37 | +-- ); |
35 | 38 | |
36 | 39 | CREATE TABLE /*$wgDBprefix*/cur ( |
37 | 40 | cur_id int(8) unsigned NOT NULL auto_increment, |
— | — | @@ -241,6 +244,7 @@ |
242 | 245 | wl_user int(5) unsigned NOT NULL, |
243 | 246 | wl_namespace tinyint(2) unsigned NOT NULL default '0', |
244 | 247 | wl_title varchar(255) binary NOT NULL default '', |
| 248 | + wl_notificationtimestamp varchar(14) binary NOT NULL default '0', |
245 | 249 | UNIQUE KEY (wl_user, wl_namespace, wl_title), |
246 | 250 | KEY namespace_title (wl_namespace,wl_title) |
247 | 251 | ); |
Index: trunk/phase3/skins/chick/main.css |
— | — | @@ -430,3 +430,18 @@ |
431 | 431 | span.newpage, span.minor { |
432 | 432 | font-weight: bold; |
433 | 433 | } |
| 434 | + |
| 435 | +span.updatedmarker { |
| 436 | + color:black; |
| 437 | + background-color:#00FF00; |
| 438 | +} |
| 439 | +span.newpageletter { |
| 440 | + font-weight:bold |
| 441 | + color:black; |
| 442 | + background-color:yellow; |
| 443 | +} |
| 444 | +span.minoreditletter { |
| 445 | + color:black; |
| 446 | + background-color:#C5FFE6; |
| 447 | +} |
| 448 | + |
Index: trunk/phase3/skins/monobook/main.css |
— | — | @@ -935,3 +935,17 @@ |
936 | 936 | .sharedUploadNotice { |
937 | 937 | font-style: italic; |
938 | 938 | } |
| 939 | + |
| 940 | +span.updatedmarker { |
| 941 | + color:black; |
| 942 | + background-color:#00FF00; |
| 943 | +} |
| 944 | +span.newpageletter { |
| 945 | + font-weight:bold |
| 946 | + color:black; |
| 947 | + background-color:yellow; |
| 948 | +} |
| 949 | +span.minoreditletter { |
| 950 | + color:black; |
| 951 | + background-color:#C5FFE6; |
| 952 | +} |
Index: trunk/phase3/skins/common/common.css |
— | — | @@ -212,3 +212,16 @@ |
213 | 213 | color:red; |
214 | 214 | } |
215 | 215 | |
| 216 | +span.updatedmarker { |
| 217 | + color:black; |
| 218 | + background-color:#00FF00; |
| 219 | +} |
| 220 | +span.newpageletter { |
| 221 | + font-weight:bold |
| 222 | + color:black; |
| 223 | + background-color:yellow; |
| 224 | +} |
| 225 | +span.minoreditletter { |
| 226 | + color:black; |
| 227 | + background-color:#C5FFE6; |
| 228 | +} |
Index: trunk/phase3/skins/MonoBook.php |
— | — | @@ -180,11 +180,13 @@ |
181 | 181 | <ul id="f-list"> |
182 | 182 | <?php if($this->data['lastmod' ]) { ?><li id="f-lastmod"><?php $this->html('lastmod') ?></li><?php } ?> |
183 | 183 | <?php if($this->data['viewcount' ]) { ?><li id="f-viewcount"><?php $this->html('viewcount') ?></li><?php } ?> |
| 184 | + <?php if($this->data['numberofwatchingusers' ]) { ?><li id="f-numberofwatchingusers"><?php $this->html('numberofwatchingusers') ?></li><?php } ?> |
184 | 185 | <?php if($this->data['credits' ]) { ?><li id="f-credits"><?php $this->html('credits') ?></li><?php } ?> |
185 | 186 | <?php if($this->data['copyright' ]) { ?><li id="f-copyright"><?php $this->html('copyright') ?></li><?php } ?> |
186 | 187 | <?php if($this->data['about' ]) { ?><li id="f-about"><?php $this->html('about') ?></li><?php } ?> |
187 | 188 | <?php if($this->data['disclaimer']) { ?><li id="f-disclaimer"><?php $this->html('disclaimer') ?></li><?php } ?> |
188 | 189 | </ul> |
| 190 | + <?php if($data['tagline']) { ?><li id="f-tagline"><?php echo $data['tagline'] ?></li><?php } ?> |
189 | 191 | </div> |
190 | 192 | </div> |
191 | 193 | <?php $this->html('reporttime') ?> |
Index: trunk/phase3/skins/amethyst/main.css |
— | — | @@ -967,3 +967,17 @@ |
968 | 968 | span.searchmatch { |
969 | 969 | color: red; |
970 | 970 | } |
| 971 | + |
| 972 | +span.updatedmarker { |
| 973 | + color:black; |
| 974 | + background-color:#00FF00; |
| 975 | +} |
| 976 | +span.newpageletter { |
| 977 | + font-weight:bold |
| 978 | + color:black; |
| 979 | + background-color:yellow; |
| 980 | +} |
| 981 | +span.minoreditletter { |
| 982 | + color:black; |
| 983 | + background-color:#C5FFE6; |
| 984 | +} |
Index: trunk/phase3/README |
— | — | @@ -59,6 +59,10 @@ |
60 | 60 | http://meta.wikimedia.org/wiki/MediaWiki_User%27s_Guide |
61 | 61 | http://meta.wikipedia.org/wiki/MediaWiki_development |
62 | 62 | |
| 63 | +Documentation about the E-Mail notification can be found on: |
| 64 | + |
| 65 | + http://meta.wikipedia.org/Enotif |
| 66 | + |
63 | 67 | If you are setting up your own wiki based on this software, it is highly |
64 | 68 | recommended that you subscribe to mediawiki-l: |
65 | 69 | |
Index: trunk/phase3/config/index.php |
— | — | @@ -80,7 +80,7 @@ |
81 | 81 | |
82 | 82 | <b><a href="http://www.mediawiki.org/">MediaWiki</a></b> is |
83 | 83 | Copyright (C) 2001-2004 by Magnus Manske, Brion Vibber, Lee Daniel Crocker, |
84 | | - Tim Starling, Erik Möller, Gabriel Wicke and others.</p> |
| 84 | + Tim Starling, Erik Möller, Gabriel Wicke, Thomas Gries and others.</p> |
85 | 85 | |
86 | 86 | <ul> |
87 | 87 | <li><a href="../README">Readme</a></li> |
— | — | @@ -387,6 +387,12 @@ |
388 | 388 | $errs["MCServers"] = "Please specify at least one server if you wish to use memcached"; |
389 | 389 | } |
390 | 390 | |
| 391 | +/* default values for installation */ |
| 392 | +$conf->Email =importRequest("Email", "email_enabled"); |
| 393 | +$conf->Emailuser=importRequest("Emailuser", "emailuser_enabled"); |
| 394 | +$conf->Enotif =importRequest("Enotif", "enotif_allpages"); |
| 395 | +$conf->Eauthent =importRequest("Eauthent", "eauthent_enabled"); |
| 396 | + |
391 | 397 | if( $conf->posted && ( 0 == count( $errs ) ) ) { |
392 | 398 | do { /* So we can 'continue' to end prematurely */ |
393 | 399 | $conf->Root = ($conf->RootPW != ""); |
— | — | @@ -636,7 +642,8 @@ |
637 | 643 | <dt> |
638 | 644 | This will be used as the return address for password reminders and |
639 | 645 | may be displayed in some error conditions so visitors can get in |
640 | | - touch with you. |
| 646 | + touch with you. It is also be used as the default sender address of e-mail |
| 647 | + notifications (enotifs). |
641 | 648 | </dt> |
642 | 649 | |
643 | 650 | <dd> |
— | — | @@ -733,6 +740,87 @@ |
734 | 741 | use Turck shared memory if the wiki will be running on a single Apache server. |
735 | 742 | </dl> |
736 | 743 | |
| 744 | +<h2>E-mail, e-mail notification and authentification setup</h2> |
| 745 | + |
| 746 | +<dl class="setup"> |
| 747 | + <dd> |
| 748 | + <label class='column'>E-mail (general)</label> |
| 749 | + <div>Select one:</div> |
| 750 | + |
| 751 | + <ul class="plain"> |
| 752 | + <li><?php aField( $conf, "Email", "enabled", "radio", "email_enabled" ); ?></li> |
| 753 | + <li><?php aField( $conf, "Email", "disabled", "radio", "email_disabled" ); ?></li> |
| 754 | + </ul> |
| 755 | + </dd> |
| 756 | + <dt> |
| 757 | + Use this to disable all e-mail functions (send a password reminder, user-to-user e-mail and e-mail notification), |
| 758 | + if sending e-mails on your server doesn't work. |
| 759 | + </dt> |
| 760 | + <dd> |
| 761 | + <label class='column'>User-to-user e-mail</label> |
| 762 | + <div>Select one:</div> |
| 763 | + |
| 764 | + <ul class="plain"> |
| 765 | + <li><?php aField( $conf, "Emailuser", "enabled", "radio", "emailuser_enabled" ); ?></li> |
| 766 | + <li><?php aField( $conf, "Emailuser", "disabled", "radio", "emailuser_disabled" ); ?></li> |
| 767 | + </ul> |
| 768 | + </dd> |
| 769 | + <dt> |
| 770 | + Use this to disable only the user-to-user e-mail function (EmailUser). |
| 771 | + </dt> |
| 772 | + <dd> |
| 773 | + <label class='column'>E-mail notification</label> |
| 774 | + <div>Select one:</div> |
| 775 | + |
| 776 | + <ul class="plain"> |
| 777 | + <li><?php aField( $conf, "Enotif", "disabled", "radio", "enotif_disabled" ); ?></li> |
| 778 | + <li><?php aField( $conf, "Enotif", "enabled for changes of watch-listed and user_talk pages (recommended for small wikis; perhaps not suited for large wikis)", "radio", "enotif_allpages" ); ?></li> |
| 779 | + <li><?php aField( $conf, "Enotif", "enabled for changes of user_talk pages only (suited for small and large wikis)", "radio", "enotif_usertalk" ); ?></li> |
| 780 | + </ul> |
| 781 | + </dd> |
| 782 | + <dt> |
| 783 | + <p><?php |
| 784 | + $ccEnotif = htmlspecialchars( 'http://meta.wikipedia.org/Enotif' ); |
| 785 | + print "<a href=\"$ccEnotif\">E-mail notification</a>"; |
| 786 | + ?> |
| 787 | + sends a notification e-mail to a user, when the user_talk page is changed |
| 788 | + and/or when watch-listed pages are changed, depending on the above settings. |
| 789 | + When testing this feature, be reminded, that obviously an e-mail address must be present in your preferences |
| 790 | + and that your own changes never trigger notifications to be sent to yourself.</p> |
| 791 | + |
| 792 | + <p>Users get corresponding options to select or deselect in their users' preferences. |
| 793 | + The user options are not shown on the preference page, if e-mail notification is disabled.</p> |
| 794 | + |
| 795 | + <p>There are additional options for fine tuning in /includes/DefaultSettings.php .</p> |
| 796 | + </dt> |
| 797 | + |
| 798 | + <dd> |
| 799 | + <label class='column'>E-mail address authentication</label> |
| 800 | + <div>Select one:</div> |
| 801 | + |
| 802 | + <ul class="plain"> |
| 803 | + <li><?php aField( $conf, "Eauthent", "disabled", "radio", "eauthent_disabled" ); ?></li> |
| 804 | + <li><?php aField( $conf, "Eauthent", "enabled", "radio", "eauthent_enabled" ); ?></li> |
| 805 | + </ul> |
| 806 | + </dd> |
| 807 | + <dt> |
| 808 | + <p><?php |
| 809 | + $ccEauthent = htmlspecialchars( 'http://meta.wikipedia.org/Eauthent' ); |
| 810 | + print "<a href=\"$ccEnotif\">E-mail address authentication</a>"; |
| 811 | + ?> |
| 812 | + uses a scheme to authenticate e-mail addresses of the users. The user who initially enters or who changes his/her stored e-mail address |
| 813 | + gets a one-time temporary password mailed to that address. The user can use the original password as long as wanted, however, the stored e-mail address |
| 814 | + is only authenticated at the moment when the user logs in with the one-time temporary password.<p> |
| 815 | + |
| 816 | + <p>The e-mail address stays authenticated as long as the user does not change it; the time of authentication is indicated |
| 817 | + on the user preference page.</p> |
| 818 | + |
| 819 | + <p>If the option is enabled, only authenticated e-mail addresses can receive EmailUser mails and/or |
| 820 | + e-mail notification mails.</p> |
| 821 | + </dt> |
| 822 | + |
| 823 | + </dl> |
| 824 | + |
737 | 825 | <h2>Database config</h2> |
738 | 826 | |
739 | 827 | <dl class="setup"> |
— | — | @@ -853,6 +941,30 @@ |
854 | 942 | $turck = '#'; |
855 | 943 | } |
856 | 944 | |
| 945 | + if ( $conf->Email == 'email_enabled' ) { |
| 946 | + $enableemail = 'true'; |
| 947 | + $enableuseremail = ( $conf->Emailuser == 'emailuser_enabled' ) ? 'true' : 'false' ; |
| 948 | + $eauthent = ( $conf->Eauthent == 'eauthent_enabled' ) ? 'true' : 'false' ; |
| 949 | + switch ( $conf->Enotif ) { |
| 950 | + case 'enotif_usertalk': |
| 951 | + $enotifusertalk = 'true'; |
| 952 | + $enotifwatchlist = 'false'; |
| 953 | + break; |
| 954 | + case 'enotif_allpages': |
| 955 | + $enotifusertalk = 'true'; |
| 956 | + $enotifwatchlist = 'true'; |
| 957 | + break; |
| 958 | + default: |
| 959 | + $enotifusertalk = 'false'; |
| 960 | + $enotifwatchlist = 'false'; |
| 961 | + } |
| 962 | + } else { |
| 963 | + $enableuseremail = 'false'; |
| 964 | + $enableemail = 'false'; |
| 965 | + $eauthent = 'false'; |
| 966 | + $enotifusertalk = 'false'; |
| 967 | + $enotifwatchlist = 'false'; |
| 968 | + } |
857 | 969 | |
858 | 970 | $file = @fopen( "/dev/urandom", "r" ); |
859 | 971 | if ( $file ) { |
— | — | @@ -912,9 +1024,21 @@ |
913 | 1025 | \$wgUploadPath = \"\$wgScriptPath/images\"; |
914 | 1026 | \$wgUploadDirectory = \"\$IP/images\"; |
915 | 1027 | |
| 1028 | +\$wgEnableEmail = $enableemail; |
| 1029 | +\$wgEnableUserEmail = $enableuseremail; |
| 1030 | + |
916 | 1031 | \$wgEmergencyContact = \"{$slconf['EmergencyContact']}\"; |
917 | 1032 | \$wgPasswordSender = \"{$slconf['PasswordSender']}\"; |
918 | 1033 | |
| 1034 | +## For a detailed description of the following switches see |
| 1035 | +## http://meta.wikimedia.org/Enotif and http://meta.wikimedia.org/Eauthent |
| 1036 | +## There are many more options for fine tuning available see |
| 1037 | +## /includes/DefaultSettings.php |
| 1038 | +## UPO means: this is also a user preference option |
| 1039 | +\$wgEmailNotificationForUserTalkPages = $enotifusertalk; # UPO |
| 1040 | +\$wgEmailNotificationForWatchlistPages = $enotifwatchlist; # UPO |
| 1041 | +\$wgEmailAuthentication = $eauthent; |
| 1042 | + |
919 | 1043 | \$wgDBserver = \"{$slconf['DBserver']}\"; |
920 | 1044 | \$wgDBname = \"{$slconf['DBname']}\"; |
921 | 1045 | \$wgDBuser = \"{$slconf['DBuser']}\"; |
Index: trunk/phase3/includes/SpecialRecentchangeslinked.php |
— | — | @@ -82,6 +82,7 @@ |
83 | 83 | "GROUP BY cur_id,cur_namespace,cur_title,cur_user,cur_comment,cur_user_text," . |
84 | 84 | "cur_timestamp,cur_minor_edit,cur_is_new,inverse_timestamp ORDER BY inverse_timestamp LIMIT {$limit}"; |
85 | 85 | } |
| 86 | + |
86 | 87 | $res = $dbr->query( $sql, $fname ); |
87 | 88 | |
88 | 89 | $wgOut->addHTML("< ".$sk->makeKnownLinkObj($nt, "", "redirect=no" )."<br />\n"); |
Index: trunk/phase3/includes/User.php |
— | — | @@ -23,6 +23,7 @@ |
24 | 24 | * @access private |
25 | 25 | */ |
26 | 26 | var $mId, $mName, $mPassword, $mEmail, $mNewtalk; |
| 27 | + var $mEmailAuthenticationtimestamp; |
27 | 28 | var $mRights, $mOptions; |
28 | 29 | var $mDataLoaded, $mNewpassword; |
29 | 30 | var $mSkin; |
— | — | @@ -116,6 +117,15 @@ |
117 | 118 | } |
118 | 119 | |
119 | 120 | /** |
| 121 | + * does the string match roughly an email address ? |
| 122 | + * @param string $addr email address |
| 123 | + * @static |
| 124 | + */ |
| 125 | + function isValidEmailAddr ( $addr ) { |
| 126 | + return preg_match( '/^([a-z0-9_.-]+([a-z0-9_.-]+)*\@[a-z0-9_-]+([a-z0-9_.-]+)*([a-z.]{2,})+)$/', strtolower($addr)); |
| 127 | + } |
| 128 | + |
| 129 | + /** |
120 | 130 | * probably return a random password |
121 | 131 | * @return string probably a random password |
122 | 132 | * @static |
— | — | @@ -150,10 +160,10 @@ |
151 | 161 | $this->mNewtalk = -1; |
152 | 162 | $this->mName = $wgIP; |
153 | 163 | $this->mRealName = $this->mEmail = ''; |
| 164 | + $this->mEmailAuthenticationtimestamp = 0; |
154 | 165 | $this->mPassword = $this->mNewpassword = ''; |
155 | 166 | $this->mRights = array(); |
156 | 167 | $this->mGroups = array(); |
157 | | - |
158 | 168 | // Getting user defaults only if we have an available language |
159 | 169 | if( isset( $wgContLang ) ) { |
160 | 170 | $this->loadDefaultFromLanguage(); |
— | — | @@ -394,12 +404,14 @@ |
395 | 405 | |
396 | 406 | $dbr =& wfGetDB( DB_SLAVE ); |
397 | 407 | $s = $dbr->selectRow( 'user', array( 'user_name','user_password','user_newpassword','user_email', |
| 408 | + 'user_emailauthenticationtimestamp', |
398 | 409 | 'user_real_name','user_options','user_touched', 'user_token' ), |
399 | 410 | array( 'user_id' => $this->mId ), $fname ); |
400 | 411 | |
401 | 412 | if ( $s !== false ) { |
402 | 413 | $this->mName = $s->user_name; |
403 | 414 | $this->mEmail = $s->user_email; |
| 415 | + $this->mEmailAuthenticationtimestamp = $s->user_emailauthenticationtimestamp; |
404 | 416 | $this->mRealName = $s->user_real_name; |
405 | 417 | $this->mPassword = $s->user_password; |
406 | 418 | $this->mNewpassword = $s->user_newpassword; |
— | — | @@ -458,8 +470,12 @@ |
459 | 471 | if ( $this->mNewtalk == -1 ) { |
460 | 472 | $this->mNewtalk=0; # reset talk page status |
461 | 473 | $dbr =& wfGetDB( DB_SLAVE ); |
| 474 | + extract( $dbr->tableNames( 'watchlist' ) ); |
462 | 475 | if($this->mId) { |
463 | | - $res = $dbr->select( 'user_newtalk', 1, array( 'user_id' => $this->mId ), $fname ); |
| 476 | + $sql = "SELECT wl_user FROM $watchlist |
| 477 | + WHERE wl_title='" . $dbr->strencode( str_replace( ' ', '_', $this->mName) )."' AND wl_namespace = " . NS_USER_TALK . |
| 478 | + " AND wl_user=" . $this->mId . " AND wl_notificationtimestamp != 0"; |
| 479 | + $res = $dbr->query( $sql,'User::get:Newtalk'); |
464 | 480 | |
465 | 481 | if ( $dbr->numRows($res)>0 ) { |
466 | 482 | $this->mNewtalk= 1; |
— | — | @@ -470,7 +486,11 @@ |
471 | 487 | $key = "$wgDBname:newtalk:ip:{$this->mName}"; |
472 | 488 | $newtalk = $wgMemc->get( $key ); |
473 | 489 | if( ! is_integer( $newtalk ) ){ |
474 | | - $res = $dbr->select( 'user_newtalk', 1, array( 'user_ip' => $this->mName ), $fname ); |
| 490 | + extract( $dbr->tableNames( 'watchlist' ) ); |
| 491 | + $sql = "SELECT wl_user FROM $watchlist |
| 492 | + WHERE wl_title='" . $dbr->strencode( str_replace( ' ', '_', $this->mName) )."' AND wl_namespace = " . NS_USER_TALK . |
| 493 | + " AND wl_user =" . 0 . " AND wl_notificationtimestamp != 0"; |
| 494 | + $res = $dbr->query( $sql,'User::getNewtalk'); |
475 | 495 | |
476 | 496 | $this->mNewtalk = $dbr->numRows( $res ) > 0 ? 1 : 0; |
477 | 497 | $dbr->freeResult( $res ); |
— | — | @@ -565,6 +585,11 @@ |
566 | 586 | return $this->mEmail; |
567 | 587 | } |
568 | 588 | |
| 589 | + function getEmailAuthenticationtimestamp() { |
| 590 | + $this->loadFromDatabase(); |
| 591 | + return $this->mEmailAuthenticationtimestamp; |
| 592 | + } |
| 593 | + |
569 | 594 | function setEmail( $str ) { |
570 | 595 | $this->loadFromDatabase(); |
571 | 596 | $this->mEmail = $str; |
— | — | @@ -839,12 +864,19 @@ |
840 | 865 | global $wgMemc, $wgDBname; |
841 | 866 | $fname = 'User::saveSettings'; |
842 | 867 | |
843 | | - $this->saveNewtalk(); |
| 868 | + $dbw =& wfGetDB( DB_MASTER ); |
| 869 | + if ( ! $this->getNewtalk() ) { |
| 870 | + # Delete the watchlist entry for user_talk page X watched by user X |
| 871 | + if( $this->mId ) { |
| 872 | + $dbw->delete( 'watchlist', array( 'wl_user' => $this->mId, 'wl_title' => str_replace('_', ' ', $this->mName) ,'wl_namespace' => NS_USER_TALK ), $fname ); |
| 873 | + } else { |
| 874 | + $dbw->delete( 'watchlist', array( 'wl_user' => 0, 'wl_title' => $this->mName, 'wl_namespace' => NS_USER_TALK ), $fname ); |
| 875 | + $wgMemc->delete( "$wgDBname:newtalk:ip:{$this->mName}" ); |
| 876 | + } |
| 877 | + } |
844 | 878 | |
845 | 879 | if ( 0 == $this->mId ) { return; } |
846 | 880 | |
847 | | - $dbw =& wfGetDB( DB_MASTER ); |
848 | | - |
849 | 881 | $dbw->update( 'user', |
850 | 882 | array( /* SET */ |
851 | 883 | 'user_name' => $this->mName, |
— | — | @@ -852,6 +884,7 @@ |
853 | 885 | 'user_newpassword' => $this->mNewpassword, |
854 | 886 | 'user_real_name' => $this->mRealName, |
855 | 887 | 'user_email' => $this->mEmail, |
| 888 | + 'user_emailauthenticationtimestamp' => $this->mEmailAuthenticationtimestamp, |
856 | 889 | 'user_options' => $this->encodeOptions(), |
857 | 890 | 'user_touched' => $dbw->timestamp($this->mTouched), |
858 | 891 | 'user_token' => $this->mToken |
— | — | @@ -878,38 +911,6 @@ |
879 | 912 | } |
880 | 913 | } |
881 | 914 | |
882 | | - /** |
883 | | - * Save value of new talk flag. |
884 | | - */ |
885 | | - function saveNewtalk() { |
886 | | - global $wgDBname, $wgMemc; |
887 | | - |
888 | | - $fname = 'User::saveNewtalk'; |
889 | | - |
890 | | - if ($this->getID() != 0) { |
891 | | - $field = 'user_id'; |
892 | | - $value = $this->getID(); |
893 | | - $key = "$wgDBname:user:id:$this->mId"; |
894 | | - } else { |
895 | | - $field = 'user_ip'; |
896 | | - $value = $this->mName; |
897 | | - $key = "$wgDBname:newtalk:ip:$this->mName"; |
898 | | - } |
899 | | - |
900 | | - $dbr =& wfGetDB( DB_SLAVE ); |
901 | | - $dbw =& wfGetDB( DB_MASTER ); |
902 | | - |
903 | | - $res = $dbr->selectField('user_newtalk', $field, |
904 | | - array($field => $value), $fname); |
905 | | - |
906 | | - if ($res !== false && $this->mNewtalk == 0) { |
907 | | - $dbw->delete('user_newtalk', array($field => $value), $fname); |
908 | | - $wgMemc->delete($key); |
909 | | - } else if ($res === false && $this->mNewtalk == 1) { |
910 | | - $dbw->insert('user_newtalk', array($field => $value), $fname); |
911 | | - $wgMemc->delete($key); |
912 | | - } |
913 | | - } |
914 | 915 | |
915 | 916 | /** |
916 | 917 | * Checks if a user with the given name exists, returns the ID |
— | — | @@ -943,6 +944,7 @@ |
944 | 945 | 'user_password' => $this->mPassword, |
945 | 946 | 'user_newpassword' => $this->mNewpassword, |
946 | 947 | 'user_email' => $this->mEmail, |
| 948 | + 'user_emailauthenticationtimestamp' => $this->mEmailAuthenticationtimestamp, |
947 | 949 | 'user_real_name' => $this->mRealName, |
948 | 950 | 'user_options' => $this->encodeOptions(), |
949 | 951 | 'user_token' => $this->mToken |
— | — | @@ -1087,20 +1089,22 @@ |
1088 | 1090 | * @return bool True if the given password is correct otherwise False. |
1089 | 1091 | */ |
1090 | 1092 | function checkPassword( $password ) { |
| 1093 | + global $wgAuth; |
1091 | 1094 | $this->loadFromDatabase(); |
1092 | 1095 | |
1093 | | - global $wgAuth; |
1094 | 1096 | if( $wgAuth->authenticate( $this->getName(), $password ) ) { |
1095 | 1097 | return true; |
1096 | 1098 | } elseif( $wgAuth->strict() ) { |
1097 | 1099 | /* Auth plugin doesn't allow local authentication */ |
1098 | 1100 | return false; |
1099 | 1101 | } |
1100 | | - |
1101 | 1102 | $ep = $this->encryptPassword( $password ); |
1102 | 1103 | if ( 0 == strcmp( $ep, $this->mPassword ) ) { |
1103 | 1104 | return true; |
1104 | | - } elseif ( 0 == strcmp( $ep, $this->mNewpassword ) ) { |
| 1105 | + } elseif ( ($this->mNewpassword != '') && (0 == strcmp( $ep, $this->mNewpassword )) ) { |
| 1106 | + $this->mEmailAuthenticationtimestamp = wfTimestampNow(); |
| 1107 | + $this->mNewpassword = ''; # use the temporary one-time password only once: clear it now ! |
| 1108 | + $this->saveSettings(); |
1105 | 1109 | return true; |
1106 | 1110 | } elseif ( function_exists( 'iconv' ) ) { |
1107 | 1111 | # Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted |
Index: trunk/phase3/includes/Article.php |
— | — | @@ -681,6 +681,7 @@ |
682 | 682 | function view() { |
683 | 683 | global $wgUser, $wgOut, $wgRequest, $wgOnlySysopsCanPatrol, $wgLang; |
684 | 684 | global $wgLinkCache, $IP, $wgEnableParserCache, $wgStylePath, $wgUseRCPatrol; |
| 685 | + global $wgEnotif; |
685 | 686 | $sk = $wgUser->getSkin(); |
686 | 687 | |
687 | 688 | $fname = 'Article::view'; |
— | — | @@ -806,6 +807,10 @@ |
807 | 808 | |
808 | 809 | $this->viewUpdates(); |
809 | 810 | wfProfileOut( $fname ); |
| 811 | + |
| 812 | + include_once( "UserMailer.php" ); |
| 813 | + $wgEnotif = new EmailNotification (); |
| 814 | + $wgEnotif->Clear( $wgUser->getID(), $this->mTitle->getDBkey(), $this->mTitle->getNamespace() ); |
810 | 815 | } |
811 | 816 | |
812 | 817 | /** |
— | — | @@ -878,9 +883,10 @@ |
879 | 884 | array( 'cur_namespace' => $talkns, 'cur_title' => $ttl ), $fname ); |
880 | 885 | |
881 | 886 | # standard deferred updates |
882 | | - $this->editUpdates( $text ); |
| 887 | + $this->editUpdates( $text, $summary, $isminor, $now ); |
883 | 888 | |
884 | | - $this->showArticle( $text, wfMsg( 'newarticle' ) ); |
| 889 | + $oldid = 0; # new article |
| 890 | + $this->showArticle( $text, wfMsg( 'newarticle' ), false, $isminor, $now, $summary, $oldid ); |
885 | 891 | } |
886 | 892 | |
887 | 893 | |
— | — | @@ -1094,7 +1100,7 @@ |
1095 | 1101 | } |
1096 | 1102 | } |
1097 | 1103 | # standard deferred updates |
1098 | | - $this->editUpdates( $text ); |
| 1104 | + $this->editUpdates( $text, $summary, $minor, $now ); |
1099 | 1105 | |
1100 | 1106 | |
1101 | 1107 | $urls = array(); |
— | — | @@ -1117,7 +1123,7 @@ |
1118 | 1124 | $u->doUpdate(); |
1119 | 1125 | } |
1120 | 1126 | |
1121 | | - $this->showArticle( $text, wfMsg( 'updated' ), $sectionanchor ); |
| 1127 | + $this->showArticle( $text, wfMsg( 'updated' ), $sectionanchor, $me2, $now, $summary, $oldid ); |
1122 | 1128 | } |
1123 | 1129 | return $good; |
1124 | 1130 | } |
— | — | @@ -1126,8 +1132,8 @@ |
1127 | 1133 | * After we've either updated or inserted the article, update |
1128 | 1134 | * the link tables and redirect to the new page. |
1129 | 1135 | */ |
1130 | | - function showArticle( $text, $subtitle , $sectionanchor = '' ) { |
1131 | | - global $wgOut, $wgUser, $wgLinkCache; |
| 1136 | + function showArticle( $text, $subtitle , $sectionanchor = '', $me2, $now, $summary, $oldid ) { |
| 1137 | + global $wgOut, $wgUser, $wgLinkCache, $wgEnotif; |
1132 | 1138 | |
1133 | 1139 | $wgLinkCache = new LinkCache(); |
1134 | 1140 | # Select for update |
— | — | @@ -1149,6 +1155,13 @@ |
1150 | 1156 | else |
1151 | 1157 | $r = ''; |
1152 | 1158 | $wgOut->redirect( $this->mTitle->getFullURL( $r ).$sectionanchor ); |
| 1159 | + |
| 1160 | + # this call would better fit into RecentChange::notifyEdit and RecentChange::notifyNew . |
| 1161 | + # this will be improved later (to-do) |
| 1162 | + |
| 1163 | + include_once( "UserMailer.php" ); |
| 1164 | + $wgEnotif = new EmailNotification (); |
| 1165 | + $wgEnotif->NotifyOnPageChange( $wgUser->getID(), $this->mTitle->getDBkey(), $this->mTitle->getNamespace(),$now, $summary, $me2, $oldid ); |
1153 | 1166 | } |
1154 | 1167 | |
1155 | 1168 | /** |
— | — | @@ -1857,12 +1870,10 @@ |
1858 | 1871 | # talk page |
1859 | 1872 | |
1860 | 1873 | global $wgUser; |
1861 | | - |
1862 | 1874 | if ($this->mTitle->getNamespace() == NS_USER_TALK && |
1863 | | - $this->mTitle->getText() == $wgUser->getName()) |
1864 | | - { |
1865 | | - $wgUser->setNewtalk(0); |
1866 | | - $wgUser->saveNewtalk(); |
| 1875 | + $this->mTitle->getText() == $wgUser->getName()) { |
| 1876 | + require_once( 'UserTalkUpdate.php' ); |
| 1877 | + $u = new UserTalkUpdate( 0, $this->mTitle->getNamespace(), $this->mTitle->getDBkey(), false, false, false ); |
1867 | 1878 | } |
1868 | 1879 | } |
1869 | 1880 | |
— | — | @@ -1872,7 +1883,7 @@ |
1873 | 1884 | * @private |
1874 | 1885 | * @param string $text |
1875 | 1886 | */ |
1876 | | - function editUpdates( $text ) { |
| 1887 | + function editUpdates( $text, $summary, $minoredit, $timestamp_of_pagechange) { |
1877 | 1888 | global $wgDeferredUpdateList, $wgDBname, $wgMemc; |
1878 | 1889 | global $wgMessageCache, $wgUser; |
1879 | 1890 | |
— | — | @@ -1897,15 +1908,13 @@ |
1898 | 1909 | $u = new SearchUpdate( $id, $title, $text ); |
1899 | 1910 | array_push( $wgDeferredUpdateList, $u ); |
1900 | 1911 | |
1901 | | - # If this is another user's talk page, save a |
1902 | | - # newtalk notification for them |
| 1912 | + # If this is another user's talk page, |
| 1913 | + # create a watchlist entry for this page |
1903 | 1914 | |
1904 | 1915 | if ($this->mTitle->getNamespace() == NS_USER_TALK && |
1905 | | - $shortTitle != $wgUser->getName()) |
1906 | | - { |
1907 | | - $other = User::newFromName($shortTitle); |
1908 | | - $other->setNewtalk(1); |
1909 | | - $other->saveNewtalk(); |
| 1916 | + $shortTitle != $wgUser->getName()) { |
| 1917 | + require_once( 'UserTalkUpdate.php' ); |
| 1918 | + $u = new UserTalkUpdate( 1, $this->mTitle->getNamespace(), $shortTitle, $summary, $minoredit, $timestamp_of_pagechange); |
1910 | 1919 | } |
1911 | 1920 | |
1912 | 1921 | if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { |
Index: trunk/phase3/includes/RecentChange.php |
— | — | @@ -40,6 +40,10 @@ |
41 | 41 | * lastTimestamp timestamp of previous entry, used in WHERE clause during update |
42 | 42 | * lang the interwiki prefix, automatically set in save() |
43 | 43 | * |
| 44 | + * temporary: not stored in the database |
| 45 | + * notificationtimestamp |
| 46 | + * numberofWatchingusers |
| 47 | + * |
44 | 48 | * @todo document functions and variables |
45 | 49 | * @package MediaWiki |
46 | 50 | */ |
— | — | @@ -61,6 +65,8 @@ |
62 | 66 | { |
63 | 67 | $rc = new RecentChange; |
64 | 68 | $rc->loadFromCurRow( $row ); |
| 69 | + $rc->notificationtimestamp = false; |
| 70 | + $rc->numberofWatchingusers = false; |
65 | 71 | return $rc; |
66 | 72 | } |
67 | 73 | |
Index: trunk/phase3/includes/SpecialUserlevels.php |
— | — | @@ -142,7 +142,7 @@ |
143 | 143 | |
144 | 144 | /** |
145 | 145 | * The entry form |
146 | | - * It allow a user to select or eventually add a group as well as looking up |
| 146 | + * It allows a user to select or eventually add a group as well as looking up |
147 | 147 | * for a username. |
148 | 148 | */ |
149 | 149 | function switchForm() { |
Index: trunk/phase3/includes/WatchedItem.php |
— | — | @@ -17,7 +17,12 @@ |
18 | 18 | $wl->mUser =& $user; |
19 | 19 | $wl->mTitle =& $title; |
20 | 20 | $wl->id = $user->getId(); |
21 | | - $wl->ns = $title->getNamespace() & ~1; |
| 21 | +# Patch (also) for email notification on page changes T.Gries/M.Arndt 11.09.2004 |
| 22 | +# TG patch: here we do not consider pages and their talk pages equivalent - why should we ? |
| 23 | +# The change results in talk-pages not automatically included in watchlists, when their parent page is included |
| 24 | +# $wl->ns = $title->getNamespace() & ~1; |
| 25 | + $wl->ns = $title->getNamespace(); |
| 26 | + |
22 | 27 | $wl->ti = $title->getDBkey(); |
23 | 28 | return $wl; |
24 | 29 | } |
— | — | @@ -57,13 +62,25 @@ |
58 | 63 | # REPLACE instead of INSERT because occasionally someone |
59 | 64 | # accidentally reloads a watch-add operation. |
60 | 65 | $dbw =& wfGetDB( DB_MASTER ); |
61 | | - $dbw->replace( 'watchlist', array(array('wl_user', 'wl_namespace', 'wl_title')), |
| 66 | + $dbw->replace( 'watchlist', array(array('wl_user', 'wl_namespace', 'wl_title', 'wl_notificationtimestamp')), |
62 | 67 | array( |
63 | 68 | 'wl_user' => $this->id, |
64 | | - 'wl_namespace' => $this->ns, |
| 69 | + 'wl_namespace' => ($this->ns & ~1), |
65 | 70 | 'wl_title' => $this->ti, |
| 71 | + 'wl_notificationtimestamp' => '0' |
66 | 72 | ), $fname ); |
67 | 73 | |
| 74 | + # the following code compensates the new behaviour, introduced by the enotif patch, |
| 75 | + # that every single watched page needs now to be listed in watchlist |
| 76 | + # namespace:page and namespace_talk:page need separate entries: create them |
| 77 | + $dbw->replace( 'watchlist', array(array('wl_user', 'wl_namespace', 'wl_title', 'wl_notificationtimestamp')), |
| 78 | + array( |
| 79 | + 'wl_user' => $this->id, |
| 80 | + 'wl_namespace' => ($this->ns | 1 ), |
| 81 | + 'wl_title' => $this->ti, |
| 82 | + 'wl_notificationtimestamp' => '0' |
| 83 | + ), $fname ); |
| 84 | + |
68 | 85 | global $wgMemc; |
69 | 86 | $wgMemc->set( $this->watchkey(), 1 ); |
70 | 87 | return true; |
— | — | @@ -76,10 +93,21 @@ |
77 | 94 | $dbw->delete( 'watchlist', |
78 | 95 | array( |
79 | 96 | 'wl_user' => $this->id, |
80 | | - 'wl_namespace' => $this->ns, |
| 97 | + 'wl_namespace' => ($this->ns & ~1), |
81 | 98 | 'wl_title' => $this->ti |
82 | 99 | ), $fname |
83 | 100 | ); |
| 101 | + |
| 102 | + # the following code compensates the new behaviour, introduced by the enotif patch, |
| 103 | + # that every single watched page needs now to be listed in watchlist |
| 104 | + # namespace:page and namespace_talk:page had separate entries: clear them |
| 105 | + $dbw->delete( 'watchlist', |
| 106 | + array( |
| 107 | + 'wl_user' => $this->id, |
| 108 | + 'wl_namespace' => ($this->ns | 1), |
| 109 | + 'wl_title' => $this->ti |
| 110 | + ), $fname |
| 111 | + ); |
84 | 112 | |
85 | 113 | if ( $dbw->affectedRows() ) { |
86 | 114 | global $wgMemc; |
Index: trunk/phase3/includes/SpecialUserlogin.php |
— | — | @@ -6,13 +6,8 @@ |
7 | 7 | */ |
8 | 8 | |
9 | 9 | /** |
10 | | - * |
| 10 | + * constructor |
11 | 11 | */ |
12 | | -require_once('UserMailer.php'); |
13 | | - |
14 | | -/** |
15 | | - * consutrctor |
16 | | - */ |
17 | 12 | function wfSpecialUserlogin() { |
18 | 13 | global $wgCommandLineMode; |
19 | 14 | global $wgRequest; |
— | — | @@ -36,6 +31,7 @@ |
37 | 32 | |
38 | 33 | function LoginForm( &$request ) { |
39 | 34 | global $wgLang, $wgAllowRealName, $wgEnableEmail; |
| 35 | + global $wgEmailAuthentication; |
40 | 36 | |
41 | 37 | $this->mName = $request->getText( 'wpName' ); |
42 | 38 | $this->mPassword = $request->getText( 'wpPassword' ); |
— | — | @@ -92,6 +88,7 @@ |
93 | 89 | */ |
94 | 90 | function addNewAccountMailPassword() { |
95 | 91 | global $wgOut; |
| 92 | + global $wgEmailAuthentication; |
96 | 93 | |
97 | 94 | if ('' == $this->mEmail) { |
98 | 95 | $this->mainLoginForm( wfMsg( 'noemail', htmlspecialchars( $this->mName ) ) ); |
— | — | @@ -104,20 +101,37 @@ |
105 | 102 | return; |
106 | 103 | } |
107 | 104 | |
108 | | - $u->saveSettings(); |
109 | | - $error = $this->mailPasswordInternal($u); |
| 105 | + $newadr = strtolower($this->mEmail); |
110 | 106 | |
| 107 | + # prepare for authentication and mail a temporary password to newadr |
| 108 | + if ( !$u->isValidEmailAddr( $newadr ) ) { |
| 109 | + return $this->mainLoginForm( wfMsg( 'invalidemailaddress', $error ) ); |
| 110 | + } |
| 111 | + $u->mEmail = $newadr; # new behaviour: set this new emailaddr from login-page into user database record |
| 112 | + $u->mEmailAuthenticationtimestamp = 0; # but flag as "dirty" = unauthenticated |
| 113 | + |
| 114 | + if ($wgEmailAuthentication) { |
| 115 | + $error = $this->mailPasswordInternal( $u, true, $dummy ); # mail a temporary password to the dirty address |
| 116 | + } |
| 117 | + |
111 | 118 | $wgOut->setPageTitle( wfMsg( 'accmailtitle' ) ); |
112 | 119 | $wgOut->setRobotpolicy( 'noindex,nofollow' ); |
113 | 120 | $wgOut->setArticleRelated( false ); |
114 | 121 | |
115 | | - if ( $error === '' ) { |
116 | | - $wgOut->addWikiText( wfMsg( 'accmailtext', $u->getName(), $u->getEmail() ) ); |
117 | | - $wgOut->returnToMain( false ); |
| 122 | + if ($wgEmailAuthentication) { |
| 123 | + if ($error === '') { |
| 124 | + return $this->mainLoginForm( wfMsg( 'passwordsentforemailauthentication', $u->getName() ) ); |
118 | 125 | } else { |
119 | | - $this->mainLoginForm( wfMsg( 'mailerror', $error ) ); |
| 126 | + return $this->mainLoginForm( wfMsg( 'mailerror', $error ) ); |
120 | 127 | } |
121 | | - |
| 128 | + # if user returns, that new email address gets authenticated in checkpassword() |
| 129 | + } |
| 130 | +# if ( $error === '' ) { |
| 131 | +# $wgOut->addWikiText( wfMsg( 'accmailtext', $u->getName(), $u->getEmail() ) ); |
| 132 | +# $wgOut->returnToMain( false ); |
| 133 | +# } else { |
| 134 | +# $this->mainLoginForm( wfMsg( 'mailerror', $error ) ); |
| 135 | +# } |
122 | 136 | $u = 0; |
123 | 137 | } |
124 | 138 | |
— | — | @@ -127,6 +141,7 @@ |
128 | 142 | */ |
129 | 143 | function addNewAccount() { |
130 | 144 | global $wgUser, $wgOut; |
| 145 | + global $wgEmailAuthentication; |
131 | 146 | |
132 | 147 | $u = $this->addNewAccountInternal(); |
133 | 148 | |
— | — | @@ -134,6 +149,27 @@ |
135 | 150 | return; |
136 | 151 | } |
137 | 152 | |
| 153 | + $newadr = strtolower($this->mEmail); |
| 154 | + if ($newadr != '') { # prepare for authentication and mail a temporary password to newadr |
| 155 | + if ( !$u->isValidEmailAddr( $newadr ) ) { |
| 156 | + return $this->mainLoginForm( wfMsg( 'invalidemailaddress', $error ) ); |
| 157 | + } |
| 158 | + $u->mEmail = $newadr; # new behaviour: set this new emailaddr from login-page into user database record |
| 159 | + $u->mEmailAuthenticationtimestamp = 0; # but flag as "dirty" = unauthenticated |
| 160 | + |
| 161 | + if ($wgEmailAuthentication) { |
| 162 | + # mail a temporary password to the dirty address |
| 163 | + |
| 164 | + $error = $this->mailPasswordInternal( $u, true, $dummy ); |
| 165 | + if ($error === '') { |
| 166 | + return $this->mainLoginForm( wfMsg( 'passwordsentforemailauthentication', $u->getName() ) ); |
| 167 | + } else { |
| 168 | + return $this->mainLoginForm( wfMsg( 'mailerror', $error ) ); |
| 169 | + } |
| 170 | + # if user returns, that new email address gets authenticated in checkpassword() |
| 171 | + } |
| 172 | + } |
| 173 | + |
138 | 174 | $wgUser = $u; |
139 | 175 | $wgUser->setCookies(); |
140 | 176 | |
— | — | @@ -168,7 +204,7 @@ |
169 | 205 | $u = User::newFromName( $name ); |
170 | 206 | if ( is_null( $u ) || |
171 | 207 | ( '' == $name ) || |
172 | | - preg_match( "/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/", $name ) || |
| 208 | + $wgUser->isIP( $name ) || |
173 | 209 | (strpos( $name, "/" ) !== false) || |
174 | 210 | (strlen( $name ) > $wgMaxNameChars) || |
175 | 211 | ucFirst($name) != $u->getName() ) |
— | — | @@ -229,7 +265,8 @@ |
230 | 266 | * @access private |
231 | 267 | */ |
232 | 268 | function processLogin() { |
233 | | - global $wgUser; |
| 269 | + global $wgUser, $wgLang; |
| 270 | + global $wgEmailAuthentication; |
234 | 271 | |
235 | 272 | if ( '' == $this->mName ) { |
236 | 273 | $this->mainLoginForm( wfMsg( 'noname' ) ); |
— | — | @@ -258,6 +295,15 @@ |
259 | 296 | } else { |
260 | 297 | $u->loadFromDatabase(); |
261 | 298 | } |
| 299 | + |
| 300 | + # store temporarily the status before the password check is performed |
| 301 | + $mailmsg = ''; |
| 302 | + $oldadr = strtolower($u->getEmail()); |
| 303 | + $newadr = strtolower($this->mEmail); |
| 304 | + $alreadyauthenticated = (( $u->mEmailAuthenticationtimestamp != 0 ) || ($oldadr == '')) ; |
| 305 | + |
| 306 | + # checkPassword sets EmailAuthenticationtimestamp, if the newPassword is used |
| 307 | + |
262 | 308 | if (!$u->checkPassword( $this->mPassword )) { |
263 | 309 | $this->mainLoginForm( wfMsg( 'wrongpassword' ) ); |
264 | 310 | return; |
— | — | @@ -272,13 +318,54 @@ |
273 | 319 | } |
274 | 320 | $u->setOption( 'rememberpassword', $r ); |
275 | 321 | |
| 322 | + /* check if user with correct password has entered a new email address */ |
| 323 | + if (($newadr <> '') && ($newadr <> $oldadr)) { # the user supplied a new email address on the login page |
| 324 | + |
| 325 | + # prepare for authentication and mail a temporary password to newadr |
| 326 | + if ( !$u->isValidEmailAddr( $newadr ) ) { |
| 327 | + return $this->mainLoginForm( wfMsg( 'invalidemailaddress', $error ) ); |
| 328 | + } |
| 329 | + $u->mEmail = $newadr; # new behaviour: store this new emailaddr from login-page now into user database record ... |
| 330 | + $u->mEmailAuthenticationtimestamp = 0; # ... but flag the address as "dirty" (unauthenticated) |
| 331 | + $alreadyauthenticated = false; |
| 332 | + |
| 333 | + if ($wgEmailAuthentication) { |
| 334 | + |
| 335 | + # mail a temporary one-time password to the dirty address and return here to complete the user login |
| 336 | + # if the user returns now or later using this temp. password, then the new email address $newadr |
| 337 | + # - which is already stored in his user record - gets authenticated in checkpassword() |
| 338 | + |
| 339 | + $error = $this->mailPasswordInternal( $u, false, $newpassword_temp); |
| 340 | + $u->mNewpassword = $newpassword_temp; |
| 341 | + |
| 342 | + # The temporary password is mailed. The user is logged-in as he entered his correct password |
| 343 | + # This appears to be more intuitive than alternative 2. |
| 344 | + |
| 345 | + if ($error === '') { |
| 346 | + $mailmsg = '<br>' . wfMsg( 'passwordsentforemailauthentication', $u->getName() ); |
| 347 | + } else { |
| 348 | + $mailmsg = '<br>' . wfMsg( 'mailerror', $error ) ; |
| 349 | + } |
| 350 | + } |
| 351 | + } |
| 352 | + |
276 | 353 | $wgUser = $u; |
277 | 354 | $wgUser->setCookies(); |
278 | 355 | |
| 356 | + # save all settings (incl. new email address and/or temporary password, if applicable) |
279 | 357 | $wgUser->saveSettings(); |
280 | 358 | |
| 359 | + if ( !$wgEmailAuthentication || $alreadyauthenticated ) { |
| 360 | + $authenticated = ''; |
| 361 | + $mailmsg = ''; |
| 362 | + } elseif ($u->mEmailAuthenticationtimestamp != 0) { |
| 363 | + $authenticated = ' ' . wfMsg( 'emailauthenticated', $wgLang->timeanddate( $u->mEmailAuthenticationtimestamp, true ) ); |
| 364 | + } else { |
| 365 | + $authenticated = ' ' . wfMsg( 'emailnotauthenticated' ); |
| 366 | + } |
| 367 | + |
281 | 368 | if( $this->hasSessionCookie() ) { |
282 | | - return $this->successfulLogin( wfMsg( 'loginsuccess', $wgUser->getName() ) ); |
| 369 | + return $this->successfulLogin( wfMsg( 'loginsuccess', $wgUser->getName() ) . $authenticated . $mailmsg ); |
283 | 370 | } else { |
284 | 371 | return $this->cookieRedirectCheck( 'login' ); |
285 | 372 | } |
— | — | @@ -307,39 +394,47 @@ |
308 | 395 | |
309 | 396 | $u->loadFromDatabase(); |
310 | 397 | |
311 | | - $error = $this->mailPasswordInternal( $u ); |
| 398 | + $error = $this->mailPasswordInternal( $u, true, $dummy ); |
312 | 399 | if ($error === '') { |
313 | 400 | $this->mainLoginForm( wfMsg( 'passwordsent', $u->getName() ) ); |
314 | 401 | } else { |
315 | 402 | $this->mainLoginForm( wfMsg( 'mailerror', $error ) ); |
316 | 403 | } |
317 | | - |
| 404 | + return; |
318 | 405 | } |
319 | 406 | |
320 | 407 | |
321 | 408 | /** |
322 | 409 | * @access private |
323 | 410 | */ |
324 | | - function mailPasswordInternal( $u ) { |
325 | | - global $wgDeferredUpdateList, $wgOutputEncoding; |
| 411 | + function mailPasswordInternal( $u, $savesettings = true, &$newpassword_out ) { |
326 | 412 | global $wgPasswordSender, $wgDBname, $wgIP; |
327 | 413 | global $wgCookiePath, $wgCookieDomain; |
328 | 414 | |
329 | 415 | if ( '' == $u->getEmail() ) { |
330 | 416 | return wfMsg( 'noemail', $u->getName() ); |
331 | 417 | } |
332 | | - $np = User::randomPassword(); |
| 418 | + |
| 419 | + $np = $u->randomPassword(); |
333 | 420 | $u->setNewpassword( $np ); |
334 | 421 | |
| 422 | + # we want to store this new password together with other values in the calling function |
| 423 | + $newpassword_out = $u->mNewpassword; |
| 424 | + |
| 425 | + # WHY IS THIS HERE ? SHOULDN'T IT BE User::setcookie ??? |
335 | 426 | setcookie( "{$wgDBname}Token", '', time() - 3600, $wgCookiePath, $wgCookieDomain ); |
| 427 | + |
| 428 | + if ($savesettings) { |
336 | 429 | $u->saveSettings(); |
| 430 | + } |
337 | 431 | |
338 | 432 | $ip = $wgIP; |
339 | 433 | if ( '' == $ip ) { $ip = '(Unknown)'; } |
340 | 434 | |
341 | | - $m = wfMsg( 'passwordremindertext', $ip, $u->getName(), $np ); |
| 435 | + $m = wfMsg( 'passwordremindermailbody', $ip, $u->getName(), wfUrlencode($u->getName()), $np ); |
342 | 436 | |
343 | | - $error = userMailer( $u->getEmail(), $wgPasswordSender, wfMsg( 'passwordremindertitle' ), $m ); |
| 437 | + require_once('UserMailer.php'); |
| 438 | + $error = userMailer( $u->getEmail(), $wgPasswordSender, wfMsg( 'passwordremindermailsubject' ), $m ); |
344 | 439 | |
345 | 440 | return htmlspecialchars( $error ); |
346 | 441 | } |
— | — | @@ -350,7 +445,6 @@ |
351 | 446 | */ |
352 | 447 | function successfulLogin( $msg ) { |
353 | 448 | global $wgUser; |
354 | | - global $wgDeferredUpdateList; |
355 | 449 | global $wgOut; |
356 | 450 | |
357 | 451 | # Run any hooks; ignore results |
— | — | @@ -382,6 +476,7 @@ |
383 | 477 | function mainLoginForm( $err ) { |
384 | 478 | global $wgUser, $wgOut, $wgLang; |
385 | 479 | global $wgDBname, $wgAllowRealName, $wgEnableEmail; |
| 480 | + global $wgEmailAuthentication; |
386 | 481 | |
387 | 482 | if ( '' == $this->mName ) { |
388 | 483 | if ( 0 != $wgUser->getID() ) { |
— | — | @@ -397,7 +492,6 @@ |
398 | 493 | } |
399 | 494 | $titleObj = Title::makeTitle( NS_SPECIAL, 'Userlogin' ); |
400 | 495 | |
401 | | - |
402 | 496 | require_once( 'templates/Userlogin.php' ); |
403 | 497 | $template =& new UserloginTemplate(); |
404 | 498 | |
— | — | @@ -410,9 +504,10 @@ |
411 | 505 | $template->set( 'action', $titleObj->getLocalUrl( $q ) ); |
412 | 506 | $template->set( 'error', $err ); |
413 | 507 | $template->set( 'create', $wgUser->isAllowedToCreateAccount() ); |
414 | | - $template->set( 'createemail', $wgEnableEmail && $wgUser->getID() != 0 ); |
| 508 | + $template->set( 'createemail', $wgEnableEmail && ($wgUser->getID() != 0) ); |
415 | 509 | $template->set( 'userealname', $wgAllowRealName ); |
416 | 510 | $template->set( 'useemail', $wgEnableEmail ); |
| 511 | + $template->set( 'useemailauthent', $wgEmailAuthentication ); |
417 | 512 | $template->set( 'remember', $wgUser->getOption( 'rememberpassword' ) ); |
418 | 513 | |
419 | 514 | $wgOut->setPageTitle( wfMsg( 'userlogin' ) ); |
Index: trunk/phase3/includes/SpecialRecentchanges.php |
— | — | @@ -18,6 +18,7 @@ |
19 | 19 | global $wgUser, $wgOut, $wgLang, $wgContLang, $wgTitle, $wgMemc, $wgDBname; |
20 | 20 | global $wgRequest, $wgSitename, $wgLanguageCode, $wgContLanguageCode; |
21 | 21 | global $wgFeedClasses, $wgUseRCPatrol; |
| 22 | + global $wgRCUseModStyle, $wgRCShowWatchingUsers, $wgShowUpdatedMarker; |
22 | 23 | $fname = 'wfSpecialRecentchanges'; |
23 | 24 | |
24 | 25 | # Get query parameters |
— | — | @@ -115,10 +116,13 @@ |
116 | 117 | $patrLink = $sk->makeKnownLink( $wgContLang->specialPage( 'Recentchanges' ), |
117 | 118 | $showhide[1-$hidepatrolled], wfArrayToCGI( array( 'hidepatrolled' => 1-$hidepatrolled ), $urlparams ) ); |
118 | 119 | |
| 120 | + $RCUseModStyle = ($wgRCUseModStyle && $wgUser->getOption('rcusemodstyle')) ? 'AND rc_this_oldid=0 ' : '' ; |
| 121 | + |
119 | 122 | $uid = $wgUser->getID(); |
120 | | - $sql2 = "SELECT $recentchanges.*" . ($uid ? ",wl_user" : "") . " FROM $recentchanges " . |
121 | | - ($uid ? "LEFT OUTER JOIN $watchlist ON wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace & 65534 " : "") . |
122 | | - "WHERE rc_timestamp > '{$cutoff}' {$hidem} " . |
| 123 | + # Patch for showing "updated since last visit" marker |
| 124 | + $sql2 = "SELECT $recentchanges.*" . ($uid ? ",wl_user,wl_notificationtimestamp" : "") . " FROM $recentchanges " . |
| 125 | + ($uid ? "LEFT OUTER JOIN $watchlist ON wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace " : "") . |
| 126 | + "WHERE rc_timestamp > '{$cutoff}' {$hidem} " . $RCUseModStyle . |
123 | 127 | "ORDER BY rc_timestamp DESC LIMIT {$limit}"; |
124 | 128 | |
125 | 129 | $res = $dbr->query( $sql2, DB_SLAVE, $fname ); |
— | — | @@ -161,6 +165,24 @@ |
162 | 166 | ! ( $hidepatrolled && $obj->rc_patrolled ) ) { |
163 | 167 | $rc = RecentChange::newFromRow( $obj ); |
164 | 168 | $rc->counter = $counter++; |
| 169 | + |
| 170 | + if ($wgShowUpdatedMarker |
| 171 | + && $wgUser->getOption( 'showupdated' ) |
| 172 | + && $obj->wl_notificationtimestamp |
| 173 | + && ($obj->rc_timestamp >= $obj->wl_notificationtimestamp)) { |
| 174 | + $rc->notificationtimestamp = true; |
| 175 | + } else { |
| 176 | + $rc->notificationtimestamp = false; |
| 177 | + } |
| 178 | + |
| 179 | + if ($wgRCShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' )) { |
| 180 | + $sql3 = "SELECT COUNT(*) AS n FROM $watchlist WHERE wl_title='" . $dbr->strencode($obj->rc_title) ."' AND wl_namespace=$obj->rc_namespace" ; |
| 181 | + $res3 = $dbr->query( $sql3, 'wfSpecialRecentChanges'); |
| 182 | + $x = $dbr->fetchObject( $res3 ); |
| 183 | + $rc->numberofWatchingusers = $x->n; |
| 184 | + } else { |
| 185 | + $rc->numberofWatchingusers = 0; |
| 186 | + } |
165 | 187 | $s .= $list->recentChangesLine( $rc, !empty( $obj->wl_user ) ); |
166 | 188 | --$limit; |
167 | 189 | } |
Index: trunk/phase3/includes/Setup.php |
— | — | @@ -80,8 +80,6 @@ |
81 | 81 | |
82 | 82 | $wgRequest = new WebRequest(); |
83 | 83 | |
84 | | - |
85 | | - |
86 | 84 | wfProfileOut( $fname.'-includes' ); |
87 | 85 | wfProfileIn( $fname.'-misc1' ); |
88 | 86 | global $wgUser, $wgLang, $wgContLang, $wgOut, $wgTitle; |
Index: trunk/phase3/includes/UserMailer.php |
— | — | @@ -1,10 +1,59 @@ |
2 | 2 | <?php |
| 3 | +/** Copyright (C) 2004 Thomas Gries <mail@tgries.de> |
| 4 | +# http://www.mediawiki.org/ |
| 5 | +# |
| 6 | +# This program is free software; you can redistribute it and/or modify |
| 7 | +# it under the terms of the GNU General Public License as published by |
| 8 | +# the Free Software Foundation; either version 2 of the License, or |
| 9 | +# (at your option) any later version. |
| 10 | +# |
| 11 | +# This program is distributed in the hope that it will be useful, |
| 12 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | +# GNU General Public License for more details. |
| 15 | +# |
| 16 | +# You should have received a copy of the GNU General Public License along |
| 17 | +# with this program; if not, write to the Free Software Foundation, Inc., |
| 18 | +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 19 | +# http://www.gnu.org/copyleft/gpl.html |
| 20 | +**/ |
| 21 | + |
3 | 22 | /** |
4 | 23 | * Provide mail capabilities |
5 | 24 | * |
6 | 25 | * @package MediaWiki |
7 | 26 | */ |
8 | 27 | |
| 28 | +function wfQuotedPrintable_name_and_emailaddr( $string ) { |
| 29 | + /* it takes formats like "name <emailaddr>" into account, |
| 30 | + for which the partial string "name" will be quoted-printable converted |
| 31 | + but not "<emailaddr>". |
| 32 | + |
| 33 | + The php mail() function does not accept the email address partial string |
| 34 | + to be quotedprintable, it does not accept inputs as quotedprintable("name <emailaddr>") . |
| 35 | + |
| 36 | + case 1: |
| 37 | + input: "name <emailaddr> rest" |
| 38 | + output: "quoted-printable(name) <emailaddr>" |
| 39 | + |
| 40 | + case 2: (should not happen) |
| 41 | + input: "<emailaddr> rest" |
| 42 | + output: "<emailaddr>" |
| 43 | + |
| 44 | + case 3: (should not happen) |
| 45 | + input: "name" |
| 46 | + output: "quoted-printable(name)" |
| 47 | + |
| 48 | + T. Gries 18.11.2004 |
| 49 | + */ |
| 50 | + |
| 51 | + /* do not quote printable for email address string <emailaddr>, but only for the (leading) string, usually the name */ |
| 52 | + preg_match( '/^([^<]*)?(<([A-z0-9_.-]+([A-z0-9_.-]+)*\@[A-z0-9_-]+([A-z0-9_.-]+)*([A-z.]{2,})+)>)?$/', $string, $part ); |
| 53 | + if ( !isset($part[1]) ) return $part[2]; |
| 54 | + if ( !isset($part[2]) ) return wfQuotedprintable($part[1]); |
| 55 | + return wfQuotedprintable($part[1]) . $part[2] ; |
| 56 | +} |
| 57 | + |
9 | 58 | /** |
10 | 59 | * This function will perform a direct (authenticated) login to |
11 | 60 | * a SMTP Server to use for mail relaying if 'wgSMTP' specifies an |
— | — | @@ -16,13 +65,12 @@ |
17 | 66 | * @param string $subject email's subject |
18 | 67 | * @param string $body email's text |
19 | 68 | */ |
20 | | -function userMailer( $to, $from, $subject, $body ) { |
21 | | - global $wgUser, $wgSMTP, $wgOutputEncoding, $wgErrorString; |
| 69 | +function userMailer( $to, $from, $subject, $body, $replyto=false ) { |
| 70 | + global $wgUser, $wgSMTP, $wgOutputEncoding, $wgErrorString, $wgEmergencyContact; |
22 | 71 | |
23 | | - $qto = wfQuotedPrintable( $to ); |
| 72 | + $qto = wfQuotedPrintable_name_and_emailaddr( $to ); |
24 | 73 | |
25 | | - if (is_array( $wgSMTP )) |
26 | | - { |
| 74 | + if (is_array( $wgSMTP )) { |
27 | 75 | require_once( 'Mail.php' ); |
28 | 76 | |
29 | 77 | $timestamp = time(); |
— | — | @@ -30,13 +78,16 @@ |
31 | 79 | $headers['From'] = $from; |
32 | 80 | /* removing to: field as it should be set by the send() function below |
33 | 81 | UNTESTED - Hashar */ |
34 | | -// $headers["To"] = $qto; |
| 82 | +// $headers['To'] = $qto; |
| 83 | +/* Reply-To: |
| 84 | + UNTESTED - Tom Gries */ |
| 85 | + $headers['Reply-To'] = $replyto; |
35 | 86 | $headers['Subject'] = $subject; |
36 | 87 | $headers['MIME-Version'] = '1.0'; |
37 | 88 | $headers['Content-type'] = 'text/plain; charset='.$wgOutputEncoding; |
38 | 89 | $headers['Content-transfer-encoding'] = '8bit'; |
39 | 90 | $headers['Message-ID'] = "<{$timestamp}" . $wgUser->getName() . '@' . $wgSMTP['IDHost'] . '>'; |
40 | | - $headers['X-Mailer'] = 'MediaWiki interuser e-mailer'; |
| 91 | + $headers['X-Mailer'] = 'MediaWiki mailer'; |
41 | 92 | |
42 | 93 | // Create the mail object using the Mail::factory method |
43 | 94 | $mail_object =& Mail::factory('smtp', $wgSMTP); |
— | — | @@ -50,20 +101,23 @@ |
51 | 102 | return $mailResult->getMessage(); |
52 | 103 | else |
53 | 104 | return 'Mail object return unknown error.'; |
54 | | - } |
55 | | - |
56 | | - else |
57 | | - { |
| 105 | + } else { |
| 106 | + # In the following $headers = expression we removed "Reply-To: {$from}\r\n" , because it is treated differently |
| 107 | + # (fifth parameter of the PHP mail function, see some lines below) |
58 | 108 | $headers = |
59 | 109 | "MIME-Version: 1.0\n" . |
60 | 110 | "Content-type: text/plain; charset={$wgOutputEncoding}\n" . |
61 | | - "Content-transfer-encoding: 8bit\n" . |
62 | | - "From: {$from}\n" . |
63 | | - "X-Mailer: MediaWiki interuser e-mailer"; |
| 111 | + "Content-Transfer-Encoding: 8bit\n" . |
| 112 | + "X-Mailer: MediaWiki mailer\n". |
| 113 | + 'From:' . wfQuotedPrintable_name_and_emailaddr($from) . "\n"; |
| 114 | + if ($replyto) { |
| 115 | + $headers .= 'Reply-To: '.wfQuotedPrintable_name_and_emailaddr($replyto)."\n"; |
| 116 | + } |
64 | 117 | |
65 | 118 | $wgErrorString = ''; |
66 | 119 | set_error_handler( 'mailErrorHandler' ); |
67 | | - mail( $to, $subject, $body, $headers ); |
| 120 | + # added -f parameter, see PHP manual for the fifth parameter when using the mail function |
| 121 | + mail( wfQuotedPrintable_name_and_emailaddr($to), $subject, $body, $headers, "-f{$wgEmergencyContact}\n"); |
68 | 122 | restore_error_handler(); |
69 | 123 | |
70 | 124 | return $wgErrorString; |
— | — | @@ -77,4 +131,244 @@ |
78 | 132 | global $wgErrorString; |
79 | 133 | $wgErrorString = preg_replace( "/^mail\(\): /", "", $string ); |
80 | 134 | } |
| 135 | + |
| 136 | +class EmailNotification { |
| 137 | + |
| 138 | +var $to, $subject, $body, $replyto, $from; |
| 139 | + |
| 140 | +# Patch for email notification on page changes T.Gries/M.Arndt 11.09.2004 |
| 141 | +# |
| 142 | +# This new module processes the email notifications when the current page is changed. |
| 143 | +# It looks up the table watchlist to find out which users are watching that page. |
| 144 | +# |
| 145 | +# The current implementation sends independent emails to each watching user for the following reason: |
| 146 | +# |
| 147 | +# - Each watching user will be notified about the page edit time expressed in his/her local time (UTC is shown additionally). |
| 148 | +# To achieve this, we need to find the individual timeoffset of each watching user from the preferences.. |
| 149 | +# |
| 150 | +# Suggested improvement to slack down the number of sent emails: |
| 151 | +# We could think of sending out bulk mails (bcc:user1,user2...) for all these users having the same timeoffset in their preferences. |
| 152 | +# |
| 153 | +# - Visit the documentation pages under http://meta.wikipedia.com/Enotif |
| 154 | + |
| 155 | +function NotifyOnPageChange($currentUser, $currentPage, $currentNs, $timestamp, $currentSummary, $currentMinorEdit, $oldid=false) { |
| 156 | + |
| 157 | + # we use $wgEmergencyContact as sender's address |
| 158 | + global $wgUser, $wgLang, $wgEmergencyContact; |
| 159 | + global $wgEmailNotificationForWatchlistPages, $wgEmailNotificationForMinorEdits; |
| 160 | + global $wgEmailNotificationSystembeep, $wgEmailNotificationForUserTalkPages; |
| 161 | + global $wgEmailNotificationRevealPageEditorAddress; |
| 162 | + global $wgEmailNotificationMailsSentFromPageEditor; |
| 163 | + global $wgEmailAuthentication; |
| 164 | + global $beeped; |
| 165 | + |
| 166 | + # The following code is only run, if several conditions are met: |
| 167 | + # 1. EmailNotification for pages (other than user_talk pages) must be enabled |
| 168 | + # 2. minor edits (changes) are only regarded if the global flag indicates so |
| 169 | + |
| 170 | + $isUserTalkPage = ($currentNs == NS_USER_TALK); |
| 171 | + $enotifusertalkpage = ($isUserTalkPage && $wgEmailNotificationForUserTalkPages); |
| 172 | + $enotifwatchlistpage = (!$isUserTalkPage && $wgEmailNotificationForWatchlistPages); |
| 173 | + |
| 174 | + if ( ($enotifusertalkpage || $enotifwatchlistpage) |
| 175 | + && (!$currentMinorEdit || $wgEmailNotificationForMinorEdits) ) { |
| 176 | + |
| 177 | + $dbr =& wfGetDB( DB_MASTER ); |
| 178 | + extract( $dbr->tableNames( 'watchlist' ) ); |
| 179 | + $sql = "SELECT wl_user FROM $watchlist |
| 180 | + WHERE wl_title='" . $dbr->strencode($currentPage)."' AND wl_namespace = " . $currentNs . |
| 181 | + " AND wl_user <>" . $currentUser . " AND wl_notificationtimestamp <= 1"; |
| 182 | + $res = $dbr->query( $sql,'UserMailer::NotifyOnChange'); |
| 183 | + |
| 184 | + if ( $dbr->numRows( $res ) > 0 ) { # if anyone is watching ... set up the email message text which is common for all receipients ... |
| 185 | + |
| 186 | + # This is a switch for one beep on the server when sending notification mails |
| 187 | + $beeped = false; |
| 188 | + |
| 189 | + $article->mTimestamp = $timestamp; |
| 190 | + $article->mSummary = $currentSummary; |
| 191 | + $article->mMinorEdit = $currentMinorEdit; |
| 192 | + $article->mNamespace = $currentNs; |
| 193 | + $article->mTitle = $currentPage; |
| 194 | + $article->mOldid = $oldid; |
| 195 | + |
| 196 | + $mail = $this->ComposeCommonMailtext( $wgUser, $article ); |
| 197 | + $watchingUser = new User(); |
| 198 | + |
| 199 | + for ($i = 1; $i <= $dbr->numRows( $res ); $i++) { # ... now do for all watching users ... if the options fit |
| 200 | + |
| 201 | + $wuser = $dbr->fetchObject( $res ); |
| 202 | + $watchingUser->setID($wuser->wl_user); |
| 203 | + if ( ( $enotifwatchlistpage && $watchingUser->getOption('enotifwatchlistpages') ) || |
| 204 | + ( $enotifusertalkpage && $watchingUser->getOption('enotifusertalkpages') ) |
| 205 | + && (!$currentMinorEdit || ($wgEmailNotificationForMinorEdits && $watchingUser->getOption('enotifminoredits') ) ) |
| 206 | + && ($watchingUser->getEmail() != '') |
| 207 | + && (!$wgEmailAuthentication || ($watchingUser->getEmailAuthenticationtimestamp() != 0 ) ) ) { |
| 208 | + # ... adjust remaining text and page edit time placeholders |
| 209 | + # which needs to be personalized for each user |
| 210 | + $sent = $this->ComposeAndSendPersonalisedMail( $watchingUser, $mail, $article ); |
| 211 | + /* the beep here beeps once when a watched-listed page is changed */ |
| 212 | + if ($sent && !$beeped && ($wgEmailNotificationSystembeep != '') ) { |
| 213 | + $last_line = system($wgEmailNotificationSystembeep); |
| 214 | + $beeped=true; |
| 215 | + } |
| 216 | + } # if the watching user has an email address in the preferences |
| 217 | + # mark the changed watch-listed page with a timestamp, so that the page is listed with an "updated since your last visit" icon in the watch list, ... |
| 218 | + # ... no matter, if the watching user has or has not indicated an email address in his/her preferences. |
| 219 | + # We memorise the event of sending out a notification and use this as a flag to suppress further mails for changes on the same page for that watching user |
| 220 | + $dbw =& wfGetDB( DB_MASTER ); |
| 221 | + $succes = $dbw->update( 'watchlist', |
| 222 | + array( /* SET */ |
| 223 | + 'wl_notificationtimestamp' => $article->mTimestamp |
| 224 | + ), array( /* WHERE */ |
| 225 | + 'wl_title' => $currentPage, |
| 226 | + 'wl_namespace' => $currentNs, |
| 227 | + 'wl_user' => $wuser->wl_user |
| 228 | + ), 'UserMailer::NotifyOnChange' |
| 229 | + ); |
| 230 | + } # for every watching user |
| 231 | + } # if anyone is watching |
| 232 | + } # if $wgEmailNotificationForWatchlistPages = true |
| 233 | +} # function NotifyOnChange |
| 234 | + |
| 235 | +function ComposeCommonMailtext ( $pageeditorUser, $article ) { |
| 236 | + |
| 237 | + global $wgLang, $wgEmergencyContact; |
| 238 | + global $wgEmailNotificationRevealPageEditorAddress, $wgEmailNotificationMailsSentFromPageEditor; |
| 239 | + global $wgNoReplyAddress; |
| 240 | + |
| 241 | + $summary = ($article->mSummary == '') ? ' - ' : $article->mSummary; |
| 242 | + $medit = ($article->mMinorEdit) ? wfMsg( 'minoredit' ) : ''; |
| 243 | + |
| 244 | + # You as the WikiAdmin and Sysops can make use of plenty of named variables when composing |
| 245 | + # your notification emails while simply editing the Meta pages |
| 246 | + |
| 247 | + $to = wfMsg( 'email_notification_to' ); |
| 248 | + $subject = wfMsg( 'email_notification_subject' ); |
| 249 | + $body = wfMsg( 'email_notification_body' ); |
| 250 | + $from = ''; /* fail safe */ |
| 251 | + $replyto = ''; /* fail safe */ |
| 252 | + |
| 253 | + # regarding the use of oldid as an indicator for the last visited version, see also |
| 254 | + # http://bugzilla.wikipeda.org/show_bug.cgi?id=603 "Delete + undelete cycle doesn't preserve old_id" |
| 255 | + # However, in the case of a new page which is already watched, we have no previous version to compare |
| 256 | + if ($article->mOldid) { |
| 257 | + $body = str_replace('$NEWPAGE', wfMsg( 'email_notification_lastvisitedrevisiontext' ), $body); |
| 258 | + $body = str_replace('$OLDID', $article->mOldid , $body); |
| 259 | + } else { |
| 260 | + $body = str_replace('$NEWPAGE', wfMsg( 'email_notification_newpagetext' ), $body ); |
| 261 | + $body = str_replace('$OLDID', '', $body); # clear $OLDID placeholder in the message template |
| 262 | + } |
| 263 | + |
| 264 | + $pagetitle = $article->mTitle; |
| 265 | + if ($article->mNamespace != 0) { $pagetitle = $wgLang->getNsText($article->mNamespace).':'.$pagetitle; }; |
| 266 | + $subject = str_replace('$PAGETITLE_QP', wfQuotedPrintable(str_replace( '_', ' ', $pagetitle)), $subject); |
| 267 | + $body = str_replace('%24PAGETITLE_RAWURL', wfUrlencode($pagetitle), $body); |
| 268 | + $body = str_replace('$PAGETITLE_RAWURL', wfUrlencode($pagetitle), $body); |
| 269 | + $body = str_replace('%24PAGETITLE', $pagetitle, $body); # needed for the {{localurl:$PAGETITLE}} in the messagetext, "$" appears here as "%24" |
| 270 | + $body = str_replace('$PAGETITLE', $pagetitle, $body); |
| 271 | + $body = str_replace('$PAGETIMESTAMP', $article->mTimestamp, $body); # this is the raw internal timestamp - can be useful, too |
| 272 | + $body = str_replace('$PAGEEDITDATEUTC', $wgLang->timeanddate( $article->mTimestamp, false, false, false, true ), $body); |
| 273 | + $body = str_replace('$PAGEMINOREDIT', $medit,$body); |
| 274 | + $body = str_replace('$PAGESUMMARY', $summary, $body); |
| 275 | + |
| 276 | + $pageeditor_qp = wfQuotedPrintable($pageeditorUser->getName()); |
| 277 | + # the user who edited is $pageeditorUser->getName(): |
| 278 | + # reveal the page editor's address as REPLY-TO address only if the user has not opted-out |
| 279 | + if (($pageeditorUser->getEmail() != '') |
| 280 | + && $pageeditorUser->getOption('enotifrevealaddr') |
| 281 | + && $wgEmailNotificationRevealPageEditorAddress ) { |
| 282 | + if ($wgEmailNotificationMailsSentFromPageEditor) { |
| 283 | + $from = $pageeditorUser->getName().' <'.$pageeditorUser->getEmail().'>'; |
| 284 | + } else { |
| 285 | + $from = 'WikiAdmin <'.$wgEmergencyContact.'>'; |
| 286 | + if ($wgEmailNotificationRevealPageEditorAddress) { |
| 287 | + $replyto = $pageeditorUser->getName().' <'.$pageeditorUser->getEmail().'>'; |
| 288 | + } |
| 289 | + } |
| 290 | + $body = str_replace('$PAGEEDITORNAMEANDEMAILADDR', $pageeditorUser->getName().' <'.$pageeditorUser->getEmail().'>', $body); |
| 291 | + } else { |
| 292 | + $from = 'WikiAdmin <'.$wgEmergencyContact.'>'; |
| 293 | + $replyto = $wgNoReplyAddress; |
| 294 | + $body = str_replace('$PAGEEDITORNAMEANDEMAILADDR', $replyto, $body); |
| 295 | + } |
| 296 | + |
| 297 | + if ($pageeditorUser->isIP($pageeditorUser->getName())) { #real anon (user:xxx.xxx.xxx.xxx) |
| 298 | + $subject = str_replace('$PAGEEDITOR_QP', 'anonymous user ' . $pageeditorUser->getName(), $subject); |
| 299 | + $body = str_replace('$PAGEEDITOR_RAWURL', wfUrlencode($pageeditorUser->getName()) . ' (anonymous user)' , $body); |
| 300 | + $body = str_replace('%24PAGEEDITOR_RAWURL', wfUrlencode($pageeditorUser->getName()) . ' (anonymous user)' , $body); |
| 301 | + $body = str_replace('%24PAGEEDITORE', $pageeditorUser->getName() . ' (anonymous user)' , $body); |
| 302 | + $body = str_replace('$PAGEEDITORE', $pageeditorUser->getName() . ' (anonymous user)' , $body); |
| 303 | + $body = str_replace('$PAGEEDITOR', 'anonymous user ' . $pageeditorUser->getName(), $body); |
| 304 | + } else { |
| 305 | + $subject = str_replace('$PAGEEDITOR_QP', $pageeditor_qp, $subject); |
| 306 | + $body = str_replace('$PAGEEDITOR_RAWURL', wfUrlencode($pageeditorUser->getName()), $body); |
| 307 | + $body = str_replace('%24PAGEEDITOR_RAWURL', wfUrlencode($pageeditorUser->getName()), $body); |
| 308 | + $body = str_replace('%24PAGEEDITORE', str_replace( ' ', '_', $pageeditorUser->getName()), $body); |
| 309 | + $body = str_replace('$PAGEEDITORE', str_replace( ' ', '_', $pageeditorUser->getName()), $body); |
| 310 | + $body = str_replace('$PAGEEDITOR',$pageeditorUser->getName(), $body); |
| 311 | + } |
| 312 | + |
| 313 | + # now save this as the constant user-independent part of the message |
| 314 | + $this->to = $to; |
| 315 | + $this->from = $from; |
| 316 | + $this->replyto = $replyto; |
| 317 | + $this->subject = $subject; |
| 318 | + $this->body = $body; |
| 319 | + return $this; |
| 320 | +} |
| 321 | + |
| 322 | + |
| 323 | +function ComposeAndSendPersonalisedMail( $watchingUser, $mail, $article) { |
| 324 | + |
| 325 | + /* returns true if the mail was sent successfully */ |
| 326 | + global $wgLang; |
| 327 | + |
| 328 | + $to = $watchingUser->getName().' <'.$watchingUser->getEmail().'>'; |
| 329 | + $body = str_replace('$WATCHINGUSERNAME', $watchingUser->getName() , $mail->body); |
| 330 | + $body = str_replace('$WATCHINGUSEREMAILADDR', $watchingUser->getEmail(), $body); |
| 331 | + |
| 332 | + $timecorrection = $watchingUser->getOption('timecorrection'); |
| 333 | + if (!$timecorrection) { $timecorrection = '00:00'; } # fail safe - I prefer it. TomGries |
| 334 | + # $PAGEEDITDATE is the time and date of the page change expressed in terms of individual local time of the notification recipient, i.e. watching user |
| 335 | + $body = str_replace('$PAGEEDITDATE', $wgLang->timeanddate($article->mTimestamp, true, false, $timecorrection, true), $body); |
| 336 | + return (userMailer($to, $mail->from, $mail->subject, $body, $mail->replyto) == ''); |
| 337 | +} |
| 338 | + |
| 339 | +function Clear($currentUser, $currentPage, $currentNs) { |
| 340 | + $dbw =& wfGetDB( DB_MASTER ); |
| 341 | + $success = $dbw->update( 'watchlist', |
| 342 | + array( /* SET */ |
| 343 | + 'wl_notificationtimestamp' => 0 |
| 344 | + ), array( /* WHERE */ |
| 345 | + 'wl_title' => $currentPage, |
| 346 | + 'wl_namespace' => $currentNs, |
| 347 | + 'wl_user' => $currentUser |
| 348 | + ), 'UserMailer::Clear' |
| 349 | + ); |
| 350 | +} |
| 351 | + |
| 352 | +function ClearAll($currentUser) { |
| 353 | + global $_REQUEST; |
| 354 | + |
| 355 | + if ($currentUser != 0) { |
| 356 | + |
| 357 | + if( $_REQUEST['reset'] == 'all') { |
| 358 | + |
| 359 | + $dbw =& wfGetDB( DB_MASTER ); |
| 360 | + $success = $dbw->update( 'watchlist', |
| 361 | + array( /* SET */ |
| 362 | + 'wl_notificationtimestamp' => 0 |
| 363 | + ), array( /* WHERE */ |
| 364 | + 'wl_user' => $currentUser |
| 365 | + ), 'UserMailer::ClearAll' |
| 366 | + ); |
| 367 | + |
| 368 | + # we also need to clear here the "you have new message" notification for the own user_talk page |
| 369 | + # This is cleared one page view later in Article::viewUpdates(); |
| 370 | + } |
| 371 | + } |
| 372 | +} |
| 373 | + |
| 374 | +} # end of class EmailNotification |
81 | 375 | ?> |
Index: trunk/phase3/includes/SpecialWatchlist.php |
— | — | @@ -17,6 +17,7 @@ |
18 | 18 | function wfSpecialWatchlist() { |
19 | 19 | global $wgUser, $wgOut, $wgLang, $wgTitle, $wgMemc, $wgRequest; |
20 | 20 | global $wgUseWatchlistCache, $wgWLCacheTimeout, $wgDBname; |
| 21 | + global $wgEnotif, $wgShowUpdatedMarker, $wgRCShowWatchingUsers; |
21 | 22 | $fname = "wfSpecialWatchlist"; |
22 | 23 | |
23 | 24 | $wgOut->setPagetitle( wfMsg( "watchlist" ) ); |
— | — | @@ -38,6 +39,12 @@ |
39 | 40 | $remove = $wgRequest->getVal( 'remove' ); |
40 | 41 | $id = $wgRequest->getVal( 'id' ); |
41 | 42 | |
| 43 | + $wgOut->addHTML( wfMsg( "email_notification_infotext" ) ); |
| 44 | + |
| 45 | + include_once( "UserMailer.php" ); |
| 46 | + $wgEnotif = new EmailNotification (); |
| 47 | + $wgEnotif->ClearAll($wgUser->getID()); |
| 48 | + |
42 | 49 | if(($action == "submit") && isset($remove) && is_array($id)) { |
43 | 50 | $wgOut->addHTML( wfMsg( "removingchecked" ) ); |
44 | 51 | foreach($id as $one) { |
— | — | @@ -70,9 +77,14 @@ |
71 | 78 | extract( $dbr->tableNames( 'cur', 'watchlist', 'recentchanges' ) ); |
72 | 79 | |
73 | 80 | $sql = "SELECT COUNT(*) AS n FROM $watchlist WHERE wl_user=$uid"; |
74 | | - $res = $dbr->query( $sql ); |
| 81 | + $res = $dbr->query( $sql, $fname ); |
75 | 82 | $s = $dbr->fetchObject( $res ); |
| 83 | + |
| 84 | +# Patch *** A1 *** (see A2 below) |
| 85 | +# adjust for page X, talk:page X, which are both stored separately, but treated together |
| 86 | +# $nitems = $s->n / 2; |
76 | 87 | $nitems = $s->n; |
| 88 | + |
77 | 89 | if($nitems == 0) { |
78 | 90 | $wgOut->addHTML( wfMsg( "nowatchlist" ) ); |
79 | 91 | return; |
— | — | @@ -99,7 +111,7 @@ |
100 | 112 | ( $cutoff = $dbr->timestamp( time() - intval( $days * 86400 ) ) ) |
101 | 113 | . "'"; |
102 | 114 | $sql = "SELECT COUNT(*) AS n FROM $cur WHERE cur_timestamp>'$cutoff'"; |
103 | | - $res = $dbr->query( $sql ); |
| 115 | + $res = $dbr->query( $sql, $fname ); |
104 | 116 | $s = $dbr->fetchObject( $res ); |
105 | 117 | $npages = $s->n; |
106 | 118 | |
— | — | @@ -113,8 +125,13 @@ |
114 | 126 | $specialTitle->escapeLocalUrl( "action=submit" ) . |
115 | 127 | "' method='post'>\n" . |
116 | 128 | "<ul>\n" ); |
| 129 | + |
| 130 | +# Patch A2 |
| 131 | +# The following was proposed by KTurner 07.11.2004 to T.Gries |
| 132 | +# $sql = "SELECT distinct (wl_namespace & ~1),wl_title FROM $watchlist WHERE wl_user=$uid"; |
117 | 133 | $sql = "SELECT wl_namespace,wl_title FROM $watchlist WHERE wl_user=$uid"; |
118 | | - $res = $dbr->query( $sql ); |
| 134 | + |
| 135 | + $res = $dbr->query( $sql, $fname ); |
119 | 136 | $sk = $wgUser->getSkin(); |
120 | 137 | while( $s = $dbr->fetchObject( $res ) ) { |
121 | 138 | $t = Title::makeTitle( $s->wl_namespace, $s->wl_title ); |
— | — | @@ -145,11 +162,17 @@ |
146 | 163 | if( $cutoff && ( $nitems*1.15 > $npages ) ) { |
147 | 164 | $x = "cur_timestamp"; |
148 | 165 | $y = wfMsg( "watchmethod-recent" ); |
149 | | - $z = "wl_namespace=cur_namespace&65534"; |
| 166 | + # TG patch: here we do not consider pages and their talk pages equivalent - why should we ? |
| 167 | + # The change results in talk-pages not automatically included in watchlists, when their parent page is included |
| 168 | + # $z = "wl_namespace=cur_namespace & ~1"; |
| 169 | + $z = "wl_namespace=cur_namespace"; |
150 | 170 | } else { |
151 | 171 | $x = "name_title_timestamp"; |
152 | 172 | $y = wfMsg( "watchmethod-list" ); |
153 | | - $z = "(wl_namespace=cur_namespace OR wl_namespace+1=cur_namespace)"; |
| 173 | + # TG patch: here we do not consider pages and their talk pages equivalent - why should we ? |
| 174 | + # The change results in talk-pages not automatically included in watchlists, when their parent page is included |
| 175 | + # $z = "(wl_namespace=cur_namespace OR wl_namespace+1=cur_namespace)"; |
| 176 | + $z = "wl_namespace=cur_namespace"; |
154 | 177 | } |
155 | 178 | |
156 | 179 | |
— | — | @@ -160,7 +183,7 @@ |
161 | 184 | $use_index = $dbr->useIndexClause( $x ); |
162 | 185 | $sql = "SELECT |
163 | 186 | cur_namespace,cur_title,cur_comment, cur_id, |
164 | | - cur_user,cur_user_text,cur_timestamp,cur_minor_edit,cur_is_new |
| 187 | + cur_user,cur_user_text,cur_timestamp,cur_minor_edit,cur_is_new,wl_notificationtimestamp |
165 | 188 | FROM $watchlist,$cur $use_index |
166 | 189 | WHERE wl_user=$uid |
167 | 190 | AND $z |
— | — | @@ -194,7 +217,23 @@ |
195 | 218 | # Make fake RC entry |
196 | 219 | $rc = RecentChange::newFromCurRow( $obj ); |
197 | 220 | $rc->counter = $counter++; |
198 | | - $s .= $list->recentChangesLine( $rc, true ); |
| 221 | + |
| 222 | + if ($wgShowUpdatedMarker && $wgUser->getOption( 'showupdated' )) { |
| 223 | + $rc->notificationtimestamp = $obj->wl_notificationtimestamp; |
| 224 | + } else { |
| 225 | + $rc->notificationtimestamp = false; |
| 226 | + } |
| 227 | + |
| 228 | + if ($wgRCShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' )) { |
| 229 | + $sql3 = "SELECT COUNT(*) AS n FROM $watchlist WHERE wl_title='" .wfStrencode($obj->cur_title). "' AND wl_namespace='{$obj->cur_namespace}'" ; |
| 230 | + $res3 = $dbr->query( $sql3, DB_READ, $fname ); |
| 231 | + $x = $dbr->fetchObject( $res3 ); |
| 232 | + $rc->numberofWatchingusers = $x->n; |
| 233 | + } else { |
| 234 | + $rc->numberofWatchingusers = 0; |
| 235 | + } |
| 236 | + |
| 237 | + $s .= $list->recentChangesLine( $rc, true); |
199 | 238 | } |
200 | 239 | $s .= $list->endRecentChangesList(); |
201 | 240 | |
Index: trunk/phase3/includes/SpecialEmailuser.php |
— | — | @@ -19,7 +19,7 @@ |
20 | 20 | } |
21 | 21 | |
22 | 22 | if ( 0 == $wgUser->getID() || |
23 | | - ( false === strpos( $wgUser->getEmail(), "@" ) ) ) { |
| 23 | + ( !$wgUser->isValidEmailAddr( $wgUser->getEmail() ) ) ) { |
24 | 24 | $wgOut->errorpage( "mailnologin", "mailnologintext" ); |
25 | 25 | return; |
26 | 26 | } |
— | — | @@ -48,8 +48,9 @@ |
49 | 49 | |
50 | 50 | $address = $nu->getEmail(); |
51 | 51 | |
52 | | - if ( ( false === strpos( $address, "@" ) ) || |
53 | | - ( 1 == $nu->getOption( "disablemail" ) ) ) { |
| 52 | + if ( ( !$nu->isValidEmailAddr( $address ) ) || |
| 53 | + ( 1 == $nu->getOption( "disablemail" ) ) || |
| 54 | + ( 0 == $nu->getEmailauthenticationtimestamp() ) ) { |
54 | 55 | $wgOut->errorpage( "noemailtitle", "noemailtext" ); |
55 | 56 | return; |
56 | 57 | } |
Index: trunk/phase3/includes/ChangesList.php |
— | — | @@ -79,6 +79,10 @@ |
80 | 80 | if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ; |
81 | 81 | $r .= $link ; |
82 | 82 | |
| 83 | + if ($rcObj->notificationtimestamp) { |
| 84 | + $r .= wfMsg( 'updatedmarker' ); |
| 85 | + } |
| 86 | + |
83 | 87 | # Diff |
84 | 88 | $r .= ' (' ; |
85 | 89 | $r .= $rcObj->difflink ; |
— | — | @@ -97,6 +101,10 @@ |
98 | 102 | $r .= $wgContLang->emphasize( ' ('.$rc_comment.')' ); |
99 | 103 | } |
100 | 104 | |
| 105 | + if ($rcObj->numberofWatchingusers > 0) { |
| 106 | + $r .= wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($rcObj->numberofWatchingusers)); |
| 107 | + } |
| 108 | + |
101 | 109 | $r .= "<br />\n" ; |
102 | 110 | return $r ; |
103 | 111 | } |
— | — | @@ -158,9 +166,9 @@ |
159 | 167 | else $r .= ' ' ; |
160 | 168 | $r .= ' ' ; # Minor |
161 | 169 | if ( $unpatrolled ) { |
162 | | - $r .= "!"; |
| 170 | + $r .= '!'; |
163 | 171 | } else { |
164 | | - $r .= " "; |
| 172 | + $r .= ' '; |
165 | 173 | } |
166 | 174 | |
167 | 175 | # Timestamp |
— | — | @@ -172,6 +180,10 @@ |
173 | 181 | if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ; |
174 | 182 | $r .= $link ; |
175 | 183 | |
| 184 | + if ($block[0]->notificationtimestamp) { |
| 185 | + $r .= wfMsg( 'updatedmarker' ); |
| 186 | + } |
| 187 | + |
176 | 188 | $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id']; |
177 | 189 | if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) { |
178 | 190 | # Changes |
— | — | @@ -187,6 +199,10 @@ |
188 | 200 | } |
189 | 201 | |
190 | 202 | $r .= $users ; |
| 203 | + |
| 204 | + if ($block[0]->numberofWatchingusers > 0) { |
| 205 | + $r .= wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($block[0]->numberofWatchingusers)); |
| 206 | + } |
191 | 207 | $r .= "<br />\n" ; |
192 | 208 | |
193 | 209 | # Sub-entries |
— | — | @@ -210,9 +226,9 @@ |
211 | 227 | } |
212 | 228 | |
213 | 229 | if ( $rcObj->unpatrolled ) { |
214 | | - $r .= "!"; |
| 230 | + $r .= '!'; |
215 | 231 | } else { |
216 | | - $r .= " "; |
| 232 | + $r .= ' '; |
217 | 233 | } |
218 | 234 | |
219 | 235 | $r .= ' </tt>' ; |
— | — | @@ -271,7 +287,7 @@ |
272 | 288 | * Either returns the line, or caches it for later use |
273 | 289 | */ |
274 | 290 | function recentChangesLine( &$rc, $watched = false ) { |
275 | | - global $wgUser ; |
| 291 | + global $wgUser; |
276 | 292 | $usenew = $wgUser->getOption( 'usenewrc' ); |
277 | 293 | if ( $usenew ) |
278 | 294 | $line = $this->recentChangesLineNew ( $rc, $watched ) ; |
— | — | @@ -280,6 +296,7 @@ |
281 | 297 | return $line ; |
282 | 298 | } |
283 | 299 | |
| 300 | + |
284 | 301 | function recentChangesLineOld( &$rc, $watched = false ) { |
285 | 302 | $fname = 'Skin::recentChangesLineOld'; |
286 | 303 | wfProfileIn( $fname ); |
— | — | @@ -350,9 +367,9 @@ |
351 | 368 | $s .= ') . . '; |
352 | 369 | |
353 | 370 | # M, N and ! (minor, new and unpatrolled) |
354 | | - if ( $rc_minor ) { $s .= ' <span class="minor">'.$message["minoreditletter"].'</span>'; } |
355 | | - if ( $rc_type == RC_NEW ) { $s .= '<span class="newpage">'.$message["newpageletter"].'</span>'; } |
356 | | - if ( $unpatrolled ) { $s .= ' <span class="unpatrolled">!</span>'; } |
| 371 | + if ( $rc_minor ) { $s .= ' <span class="minoreditletter">'.$message["minoreditletter"].'</span>'; } |
| 372 | + if ( $rc_type == RC_NEW ) { $s .= '<span class="newpageletter">'.$message["newpageletter"].'</span>'; } |
| 373 | + if ( !$rc_patrolled ) { $s .= ' <span class="unpatrolled">!</span>'; } |
357 | 374 | |
358 | 375 | # Article link |
359 | 376 | # If it's a new article, there is no diff link, but if it hasn't been |
— | — | @@ -365,6 +382,11 @@ |
366 | 383 | if ( $watched ) { |
367 | 384 | $articleLink = '<strong>'.$articleLink.'</strong>'; |
368 | 385 | } |
| 386 | + |
| 387 | + if ($rc->notificationtimestamp) { |
| 388 | + $articleLink .= wfMsg( 'updatedmarker' ); |
| 389 | + } |
| 390 | + |
369 | 391 | $s .= ' '.$articleLink; |
370 | 392 | wfProfileOut("$fname-page"); |
371 | 393 | } |
— | — | @@ -412,6 +434,11 @@ |
413 | 435 | $rc_comment = $this->skin->formatComment($rc_comment,$rc->getTitle()); |
414 | 436 | $s .= $wgContLang->emphasize(' (' . $rc_comment . ')'); |
415 | 437 | } |
| 438 | + |
| 439 | + if ($rc->numberofWatchingusers > 0) { |
| 440 | + $s .= ' ' . wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($rc->numberofWatchingusers)); |
| 441 | + } |
| 442 | + |
416 | 443 | $s .= "</li>\n"; |
417 | 444 | |
418 | 445 | wfProfileOut( "$fname-rest" ); |
— | — | @@ -477,6 +504,8 @@ |
478 | 505 | $rc->watched = $watched ; |
479 | 506 | $rc->link = $clink ; |
480 | 507 | $rc->timestamp = $time; |
| 508 | + $rc->notificationtimestamp = $baseRC->notificationtimestamp; |
| 509 | + $rc->numberofWatchingusers = $baseRC->numberofWatchingusers; |
481 | 510 | |
482 | 511 | # Make "cur" and "diff" links |
483 | 512 | $titleObj = $rc->getTitle(); |
Index: trunk/phase3/includes/SkinTemplate.php |
— | — | @@ -148,6 +148,7 @@ |
149 | 149 | global $wgMimeType, $wgOutputEncoding, $wgUseDatabaseMessages, $wgRequest; |
150 | 150 | global $wgDisableCounters, $wgLogo, $action, $wgFeedClasses, $wgSiteNotice; |
151 | 151 | global $wgMaxCredits, $wgShowCreditsIfMax; |
| 152 | + global $wgPageShowWatchingUsers; |
152 | 153 | |
153 | 154 | $fname = 'SkinTemplate::outputPage'; |
154 | 155 | wfProfileIn( $fname ); |
— | — | @@ -282,6 +283,25 @@ |
283 | 284 | $tpl->set('viewcount', false); |
284 | 285 | } |
285 | 286 | } |
| 287 | + |
| 288 | + if ($wgPageShowWatchingUsers) { |
| 289 | + $dbr =& wfGetDB( DB_SLAVE ); |
| 290 | + extract( $dbr->tableNames( 'watchlist' ) ); |
| 291 | + $sql = "SELECT COUNT(*) AS n FROM $watchlist |
| 292 | + WHERE wl_title='" . $dbr->strencode($wgTitle->getDBKey()) . |
| 293 | + "' AND wl_namespace=" . $wgTitle->getNamespace() ; |
| 294 | + $res = $dbr->query( $sql, 'SkinPHPTal::outputPage'); |
| 295 | + $x = $dbr->fetchObject( $res ); |
| 296 | + $numberofwatchingusers = $x->n; |
| 297 | + if ($numberofwatchingusers > 0) { |
| 298 | + $tpl->set('numberofwatchingusers', wfMsg('number_of_watching_users_pageview', $numberofwatchingusers)); |
| 299 | + } else { |
| 300 | + $tpl->set('numberofwatchingusers', false); |
| 301 | + }; |
| 302 | + } else { |
| 303 | + $tpl->set('numberofwatchingusers', false); |
| 304 | + } |
| 305 | + |
286 | 306 | $tpl->set('lastmod', $this->lastModified()); |
287 | 307 | $tpl->set('copyright',$this->getCopyright()); |
288 | 308 | |
— | — | @@ -316,6 +336,7 @@ |
317 | 337 | $tpl->setRef( 'debug', $out->mDebugtext ); |
318 | 338 | $tpl->set( 'reporttime', $out->reportTime() ); |
319 | 339 | $tpl->set( 'sitenotice', $wgSiteNotice ); |
| 340 | + $tpl->set( 'tagline', wfMsg('tagline') ); |
320 | 341 | |
321 | 342 | $printfooter = "<div class=\"printfooter\">\n" . $this->printSource() . "</div>\n"; |
322 | 343 | $out->mBodytext .= $printfooter ; |
Index: trunk/phase3/includes/SpecialPreferences.php |
— | — | @@ -166,6 +166,8 @@ |
167 | 167 | */ |
168 | 168 | function savePreferences() { |
169 | 169 | global $wgUser, $wgLang, $wgOut; |
| 170 | + global $wgEnableUserEmail, $wgEnableEmail; |
| 171 | + global $wgEmailAuthentication; |
170 | 172 | |
171 | 173 | if ( '' != $this->mNewpass ) { |
172 | 174 | if ( $this->mNewpass != $this->mRetypePass ) { |
— | — | @@ -179,10 +181,6 @@ |
180 | 182 | } |
181 | 183 | $wgUser->setPassword( $this->mNewpass ); |
182 | 184 | } |
183 | | - global $wgEnableEmail; |
184 | | - if( $wgEnableEmail ) { |
185 | | - $wgUser->setEmail( $this->mUserEmail ); |
186 | | - } |
187 | 185 | $wgUser->setRealName( $this->mRealName ); |
188 | 186 | $wgUser->setOption( 'language', $this->mUserLanguage ); |
189 | 187 | $wgUser->setOption( 'variant', $this->mUserVariant ); |
— | — | @@ -206,7 +204,6 @@ |
207 | 205 | $wgUser->setOption( "searchNs{$i}", $value ); |
208 | 206 | } |
209 | 207 | |
210 | | - global $wgEnableUserEmail; |
211 | 208 | if( $wgEnableEmail && $wgEnableUserEmail ) { |
212 | 209 | $wgUser->setOption( 'disablemail', $this->mEmailFlag ); |
213 | 210 | } |
— | — | @@ -216,8 +213,38 @@ |
217 | 214 | $wgUser->setOption( $tname, $tvalue ); |
218 | 215 | } |
219 | 216 | $wgUser->setCookies(); |
| 217 | + $wgUser->saveSettings(); |
220 | 218 | |
| 219 | + if( $wgEnableEmail ) { |
| 220 | + $newadr = strtolower( $this->mUserEmail ); |
| 221 | + $oldadr = strtolower($wgUser->getEmail()); |
| 222 | + if (($newadr <> '') && ($newadr <> $oldadr)) { # the user has supplied a new email address on the login page |
| 223 | + # prepare for authentication and mail a temporary password to newadr |
| 224 | + require_once( 'SpecialUserlogin.php' ); |
| 225 | + if ( !$wgUser->isValidEmailAddr( $newadr ) ) { |
| 226 | + $this->mainPrefsForm( wfMsg( 'invalidemailaddress' ) ); |
| 227 | + return; |
| 228 | + } |
| 229 | + $wgUser->mEmail = $newadr; # new behaviour: set this new emailaddr from login-page into user database record |
| 230 | + $wgUser->mEmailAuthenticationtimestamp = 0; # but flag as "dirty" = unauthenticated |
221 | 231 | $wgUser->saveSettings(); |
| 232 | + if ($wgEmailAuthentication) { |
| 233 | + # mail a temporary password to the dirty address |
| 234 | + # on "save options", this user will be logged-out automatically |
| 235 | + $error = LoginForm::mailPasswordInternal( $wgUser, true, $dummy ); |
| 236 | + if ($error === '') { |
| 237 | + return LoginForm::mainLoginForm( wfMsg( 'passwordsentforemailauthentication', $wgUser->getName() ) ); |
| 238 | + } else { |
| 239 | + return LoginForm::mainLoginForm( wfMsg( 'mailerror', $error ) ); |
| 240 | + } |
| 241 | + # if user returns, that new email address gets authenticated in checkpassword() |
| 242 | + } |
| 243 | + } else { |
| 244 | + $wgUser->setEmail( strtolower($this->mUserEmail) ); |
| 245 | + $wgUser->setCookies(); |
| 246 | + $wgUser->saveSettings(); |
| 247 | + } |
| 248 | + } |
222 | 249 | |
223 | 250 | $wgOut->setParserOptions( ParserOptions::newFromUser( $wgUser ) ); |
224 | 251 | $po = ParserOptions::newFromUser( $wgUser ); |
— | — | @@ -232,6 +259,7 @@ |
233 | 260 | |
234 | 261 | $this->mOldpass = $this->mNewpass = $this->mRetypePass = ''; |
235 | 262 | $this->mUserEmail = $wgUser->getEmail(); |
| 263 | + $this->mUserEmailAuthenticationtimestamp = $wgUser->getEmailAuthenticationtimestamp(); |
236 | 264 | $this->mRealName = ($wgAllowRealName) ? $wgUser->getRealName() : ''; |
237 | 265 | $this->mUserLanguage = $wgUser->getOption( 'language' ); |
238 | 266 | if( empty( $this->mUserLanguage ) ) { |
— | — | @@ -306,7 +334,7 @@ |
307 | 335 | } |
308 | 336 | |
309 | 337 | |
310 | | - function getToggle( $tname ) { |
| 338 | + function getToggle( $tname, $trailer = false) { |
311 | 339 | global $wgUser, $wgLang; |
312 | 340 | |
313 | 341 | $this->mUsedToggles[$tname] = true; |
— | — | @@ -317,8 +345,9 @@ |
318 | 346 | } else { |
319 | 347 | $checked = ''; |
320 | 348 | } |
| 349 | + $trailer =($trailer) ? $trailer : ''; |
321 | 350 | return "<div><input type='checkbox' value=\"1\" " |
322 | | - . "id=\"$tname\" name=\"wpOp$tname\"$checked /><label for=\"$tname\">$ttext</label></div>\n"; |
| 351 | + . "id=\"$tname\" name=\"wpOp$tname\"$checked /><label for=\"$tname\">$ttext</label>$trailer</div>\n"; |
323 | 352 | } |
324 | 353 | |
325 | 354 | /** |
— | — | @@ -328,7 +357,11 @@ |
329 | 358 | global $wgUser, $wgOut, $wgLang, $wgContLang, $wgUseDynamicDates, $wgValidSkinNames; |
330 | 359 | global $wgAllowRealName, $wgImageLimits; |
331 | 360 | global $wgLanguageNames, $wgDisableLangConversion; |
| 361 | + global $wgEmailNotificationForWatchlistPages, $wgEmailNotificationForUserTalkPages,$wgEmailNotificationForMinorEdits; |
| 362 | + global $wgRCUseModStyle, $wgRCShowWatchingUsers, $wgEmailNotificationRevealPageEditorAddress; |
| 363 | + global $wgEnableEmail, $wgEnableUserEmail, $wgEmailAuthentication; |
332 | 364 | global $wgContLanguageCode; |
| 365 | + |
333 | 366 | $wgOut->setPageTitle( wfMsg( 'preferences' ) ); |
334 | 367 | $wgOut->setArticleRelated( false ); |
335 | 368 | $wgOut->setRobotpolicy( 'noindex,nofollow' ); |
— | — | @@ -396,21 +429,50 @@ |
397 | 430 | if ( $this->mEmailFlag ) { $emfc = 'checked="checked"'; } |
398 | 431 | else { $emfc = ''; } |
399 | 432 | |
| 433 | + if ($wgEmailAuthentication && ($this->mUserEmail != '') ) { |
| 434 | + if ($wgUser->getEmailAuthenticationtimestamp() != 0) { |
| 435 | + $emailauthenticated = wfMsg('emailauthenticated',$wgLang->timeanddate($wgUser->getEmailAuthenticationtimestamp(), true ) ).'<br>'; |
| 436 | + $disabled = ''; |
| 437 | + } else { |
| 438 | + $emailauthenticated = wfMsg('emailnotauthenticated').'<br>'; |
| 439 | + $disabled = ' '.wfMsg('disableduntilauthent'); |
| 440 | + } |
| 441 | + } else { |
| 442 | + $emailauthenticated = ''; |
| 443 | + } |
| 444 | + |
| 445 | + if ($this->mUserEmail == '') { |
| 446 | + $disabled = ' '.wfMsg('disablednoemail'); |
| 447 | + } |
| 448 | + |
400 | 449 | $ps = $this->namespacesCheckboxes(); |
401 | 450 | |
| 451 | + $enotifwatchlistpages = ($wgEmailNotificationForWatchlistPages) ? $this->getToggle( 'enotifwatchlistpages', $disabled) : ''; |
| 452 | + $enotifusertalkpages = ($wgEmailNotificationForUserTalkPages) ? $this->getToggle( 'enotifusertalkpages', $disabled) : ''; |
| 453 | + $enotifminoredits = ($wgEmailNotificationForMinorEdits) ? $this->getToggle( 'enotifminoredits', $disabled) : ''; |
| 454 | + $enotifrevealaddr = ($wgEmailNotificationRevealPageEditorAddress) ? $this->getToggle( 'enotifrevealaddr', $disabled) : ''; |
| 455 | + $prefs_help_email_enotif = ( $wgEmailNotificationForWatchlistPages || $wgEmailNotificationForUserTalkPages) ? ' ' . wfMsg('prefs-help-email-enotif') : ''; |
| 456 | + $prefs_help_realname = ''; |
| 457 | + |
402 | 458 | $wgOut->addHTML( "<fieldset> |
403 | 459 | <legend>".wfMsg('prefs-personal')."</legend>"); |
| 460 | + |
404 | 461 | if ($wgAllowRealName) { |
405 | 462 | $wgOut->addHTML("<div><label>$yrn: <input type='text' name=\"wpRealName\" value=\"{$this->mRealName}\" size='20' /></label></div>"); |
| 463 | + $prefs_help_realname = wfMsg('prefs-help-realname').'<br>'; |
406 | 464 | } |
407 | 465 | |
408 | | - global $wgEnableEmail, $wgEnableUserEmail; |
409 | 466 | if( $wgEnableEmail ) { |
410 | 467 | $wgOut->addHTML(" |
411 | 468 | <div><label>$yem: <input type='text' name=\"wpUserEmail\" value=\"{$this->mUserEmail}\" size='20' /></label></div>" ); |
412 | 469 | if( $wgEnableUserEmail ) { |
413 | | - $wgOut->addHTML(" |
414 | | - <div><label><input type='checkbox' $emfc value=\"1\" name=\"wpEmailFlag\" />$emf</label></div>" ); |
| 470 | + $wgOut->addHTML( |
| 471 | + $emailauthenticated. |
| 472 | + $enotifrevealaddr. |
| 473 | + $enotifwatchlistpages. |
| 474 | + $enotifusertalkpages. |
| 475 | + $enotifminoredits. |
| 476 | + "<div><label><input type='checkbox' $emfc value=\"1\" name=\"wpEmailFlag\" />$emf.$disabled</label></div>" ); |
415 | 477 | } |
416 | 478 | } |
417 | 479 | |
— | — | @@ -465,7 +527,7 @@ |
466 | 528 | <div><label>$rpw: <input type='password' name=\"wpRetypePass\" value=\"{$this->mRetypePass}\" size='20' /></label></div> |
467 | 529 | " . $this->getToggle( "rememberpassword" ) . " |
468 | 530 | </fieldset> |
469 | | - <div class='prefsectiontip'>".wfMsg('prefs-help-userdata')."</div>\n</fieldset>\n" ); |
| 531 | + <div class='prefsectiontip'>".$prefs_help_realname.wfMsg('prefs-help-email').$prefs_help_email_enotif."</div>\n</fieldset>\n" ); |
470 | 532 | |
471 | 533 | |
472 | 534 | # Quickbar setting |
— | — | @@ -559,12 +621,15 @@ |
560 | 622 | <div class='prefsectiontip'>* {$tzt}</div> |
561 | 623 | </fieldset>\n\n" ); |
562 | 624 | |
| 625 | + $shownumberswatching = ($wgRCShowWatchingUsers) ? $this->getToggle('shownumberswatching') : ''; |
| 626 | + $rcusemodstyle = ($wgRCUseModStyle) ? $this->getToggle('rcusemodstyle') : ''; |
| 627 | + |
563 | 628 | $wgOut->addHTML( " |
564 | 629 | <fieldset><legend>".wfMsg('prefs-rc')."</legend> |
565 | | - <div><label>$rcc: <input type='text' name=\"wpRecent\" value=\"$this->mRecent\" size='6' /></label></div> |
566 | | - " . $this->getToggle( "hideminor" ) . |
567 | | - $this->getToggle( "usenewrc" ) . " |
568 | | - <div><label>$stt: <input type='text' name=\"wpStubs\" value=\"$this->mStubs\" size='6' /></label></div> |
| 630 | + <div><label>$rcc: <input type='text' name=\"wpRecent\" value=\"$this->mRecent\" size='6' /></label></div>" . |
| 631 | + $this->getToggle( "hideminor" ) . $shownumberswatching . |
| 632 | + $this->getToggle( "usenewrc" ) . $rcusemodstyle . $this->getToggle('showupdated', wfMsg('updatedmarker')) . |
| 633 | + "<div><label>$stt: <input type='text' name=\"wpStubs\" value=\"$this->mStubs\" size='6' /></label></div> |
569 | 634 | <div><label>".wfMsg('imagemaxsize')."<select name=\"wpImageSize\">"); |
570 | 635 | |
571 | 636 | $imageLimitOptions=''; |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -165,6 +165,14 @@ |
166 | 166 | $wgPasswordSender = 'Wikipedia Mail <apache@' . $wgServerName . '>'; |
167 | 167 | |
168 | 168 | /** |
| 169 | + * dummy address which should be accepted during mail send action |
| 170 | + * It might be necessay to adapt the address or to set it equal |
| 171 | + * to the $wgEmergencyContact address |
| 172 | + */ |
| 173 | +#$wgNoReplyAddress = $wgEmergencyContact; |
| 174 | +$wgNoReplyAddress = 'reply@not.possible'; |
| 175 | + |
| 176 | +/** |
169 | 177 | * Set to true to enable the e-mail basic features: |
170 | 178 | * Password reminders, etc. If sending e-mail on your |
171 | 179 | * server doesn't work, you might want to disable this. |
— | — | @@ -495,10 +503,64 @@ |
496 | 504 | # Requires zlib support enabled in PHP. |
497 | 505 | $wgUseGzip = false; |
498 | 506 | |
| 507 | +/* T. Gries Aug.-Nov.2004 |
499 | 508 | |
| 509 | + THESE ARE MY SUGGESTED FIRST TEST global admin options FOR ENOTIF. |
| 510 | + Attention: the defaults might differ from standard media wiki distributions. |
| 511 | + |
| 512 | + However, I suggest to start with these which allow to evaluate almost all new features quickly. |
| 513 | + user preferences default options SEE AS USUAL /languages/Language.php |
| 514 | +*/ |
| 515 | + |
| 516 | +########################### CAUTION ################# ATTENTION ############################################### |
| 517 | +# |
| 518 | +# T. Gries Aug.-Dec. 2004 |
| 519 | +# |
| 520 | +# SECTION FOR DEVELOPERS and SERVER ADMINS |
| 521 | +# |
| 522 | +# HERE COME TWO OPTIONS, WHICH ALLOW ACOUSTIC SIGNALS on the server beeper WHEN AN EMAIL IS ACTUALLY SENT OUT. |
| 523 | +# YOU MIGHT WISH TO ENABLE THESE, BUT BE CAREFUL, AS A system() CALL IS PERFORMED using the shown parameters. |
| 524 | +# I FIND IT VERY USEFUL, but this is a very personal comment. T. Gries |
| 525 | +# |
| 526 | +# The system speaker beeps when the wiki actually sends out a notification mail (safe default = disabled). |
| 527 | +# |
| 528 | +# The following string is passed as parameter to a system() call in UserMailer.php |
| 529 | +# The system() calls call - in the shown example - the beep 1.2.2 program (LINUX) with frequency f [Hz] and length l [msec] |
| 530 | +# |
| 531 | +# Beep 1.2.2 can be found on http://freshmeat.net/projects/beep/ and I like it. |
| 532 | +# |
| 533 | +########################### SAFE #################### SAFE ##################################################### |
| 534 | +$wgEmailNotificationSystembeep = ''; # empty string disables this feature; this appears to be safe |
| 535 | +######ENTER#AT#YOUR#OWN#RISK###CAUTION###### ATTENTION ################################################### |
| 536 | +#$wgEmailNotificationSystembeep = '/usr/bin/beep -f 4000 -l 20 &'; # a system() call with exactly this string as parameter is executed when such a mail is sent |
| 537 | +########################### CAUTION ################# ATTENTION ############################################### |
| 538 | + |
| 539 | +# For email notification on page changes T.Gries/M.Arndt 01.11.2004 |
| 540 | +$wgPasswordSender = $wgEmergencyContact; |
| 541 | +$wgEmailNotificationMailsSentFromPageEditor = false; # false: Enotif mails appear to come from $wgEmergencyContact |
| 542 | +# # true: from PageEditor if s/he opted-in |
| 543 | + |
| 544 | +# If set to true, users get a corresponding option in their preferences and can choose to enable or disable at their discretion |
| 545 | +# If set to false, the corresponding input form on the user preference page is suppressed |
| 546 | +# It call this to be a "user-preferences-option (UPO)" |
| 547 | +$wgEmailAuthentication = true; # UPO (if this is set to false, texts referring to authentication are suppressed) |
| 548 | +$wgEmailNotificationForWatchlistPages = true; # UPO |
| 549 | +$wgEmailNotificationForUserTalkPages = true; # UPO |
| 550 | +$wgEmailNotificationRevealPageEditorAddress = true; # UPO; reply-to address may be filled with page editor's address (if user allowed this in the preferences) |
| 551 | +$wgEmailNotificationForMinorEdits = true; # UPO; false: "minor edits" on pages do not trigger notification mails. |
| 552 | +# # Attention: _every_ change on a user_talk page trigger a notification mail (if the user is not yet notified) |
| 553 | + |
| 554 | +# Show recent changes in UseMod style, i.e. only the recent change of a page is listed |
| 555 | +$wgRCUseModStyle = true; # UPO |
| 556 | +# Show watching users in recent changes, watchlist and page history views |
| 557 | +$wgRCShowWatchingUsers = true; # UPO |
| 558 | +# Show watching users in Page views |
| 559 | +$wgPageShowWatchingUsers = true; |
| 560 | +# Show "Updated (since my last visit)" marker in RC view, watchlist and history view for watched pages with new changes |
| 561 | +$wgShowUpdatedMarker = true; # UPO |
| 562 | + |
500 | 563 | $wgCookieExpiration = 2592000; |
501 | 564 | |
502 | | - |
503 | 565 | # Squid-related settings |
504 | 566 | # |
505 | 567 | |
— | — | @@ -743,10 +805,10 @@ |
744 | 806 | $wgDefaultUserOptions = array(); |
745 | 807 | |
746 | 808 | # Whether or not to allow real name fields. Defaults to true. |
| 809 | +# If set to false, the corresponding input forms on the log-in page and on the user preference page is suppressed. |
747 | 810 | $wgAllowRealName = true; |
748 | 811 | |
749 | 812 | # Use XML parser? |
750 | | - |
751 | 813 | $wgUseXMLparser = false ; |
752 | 814 | |
753 | 815 | # Extensions |
Index: trunk/phase3/includes/PageHistory.php |
— | — | @@ -22,7 +22,7 @@ |
23 | 23 | # This shares a lot of issues (and code) with Recent Changes |
24 | 24 | |
25 | 25 | function history() { |
26 | | - global $wgUser, $wgOut, $wgLang; |
| 26 | + global $wgUser, $wgOut, $wgLang, $wgShowUpdatedMarker; |
27 | 27 | |
28 | 28 | # If page hasn't changed, client can cache this |
29 | 29 | |
— | — | @@ -59,8 +59,17 @@ |
60 | 60 | |
61 | 61 | $namespace = $this->mTitle->getNamespace(); |
62 | 62 | $title = $this->mTitle->getText(); |
| 63 | + $uid = $wgUser->getID(); |
| 64 | + $db =& wfGetDB( DB_SLAVE ); |
| 65 | + if ($wgShowUpdatedMarker && $wgUser->getOption( 'showupdated' )) { |
| 66 | + $dbr =& wfGetDB( DB_MASTER ); |
| 67 | + $row = $dbr->selectRow( 'watchlist', |
| 68 | + array( 'wl_notificationtimestamp' ), |
| 69 | + array( 'wl_namespace' => $namespace, 'wl_title' => $this->mTitle->getDBkey(), 'wl_user' => $wgUser->getID() ), |
| 70 | + $fname ); |
| 71 | + $notificationtimestamp = $row->wl_notificationtimestamp; |
| 72 | + } else $notificationtimestamp = false ; |
63 | 73 | |
64 | | - $db =& wfGetDB( DB_SLAVE ); |
65 | 74 | $use_index = $db->useIndexClause( 'name_title_timestamp' ); |
66 | 75 | $oldtable = $db->tableName( 'old' ); |
67 | 76 | |
— | — | @@ -103,7 +112,8 @@ |
104 | 113 | $this->mArticle->getUserText(), $namespace, |
105 | 114 | $title, 0, $this->mArticle->getComment(), |
106 | 115 | ( $this->mArticle->getMinorEdit() > 0 ), |
107 | | - $counter++ |
| 116 | + $counter++, |
| 117 | + $notificationtimestamp |
108 | 118 | ); |
109 | 119 | } |
110 | 120 | while ( $line = $db->fetchObject( $res ) ) { |
— | — | @@ -112,7 +122,8 @@ |
113 | 123 | $line->old_user_text, $namespace, |
114 | 124 | $title, $line->old_id, |
115 | 125 | $line->old_comment, ( $line->old_minor_edit > 0 ), |
116 | | - $counter++ |
| 126 | + $counter++, |
| 127 | + $notificationtimestamp |
117 | 128 | ); |
118 | 129 | } |
119 | 130 | $s .= $this->endHistoryList( !$atend ); |
— | — | @@ -143,7 +154,7 @@ |
144 | 155 | return $s; |
145 | 156 | } |
146 | 157 | |
147 | | - function historyLine( $ts, $u, $ut, $ns, $ttl, $oid, $c, $isminor, $counter = '' ) { |
| 158 | + function historyLine( $ts, $u, $ut, $ns, $ttl, $oid, $c, $isminor, $counter = '', $notificationtimestamp = false ) { |
148 | 159 | global $wgLang, $wgContLang; |
149 | 160 | |
150 | 161 | static $message; |
— | — | @@ -206,6 +217,9 @@ |
207 | 218 | $c = $this->mSkin->formatcomment( $c, $this->mTitle ); |
208 | 219 | $s .= " <em>($c)</em>"; |
209 | 220 | } |
| 221 | + if ($notificationtimestamp && ($ts >= $notificationtimestamp)) { |
| 222 | + $s .= wfMsg( 'updatedmarker' ); |
| 223 | + } |
210 | 224 | $s .= '</li>'; |
211 | 225 | |
212 | 226 | $this->lastline = $s; |
Index: trunk/phase3/includes/Skin.php |
— | — | @@ -797,8 +797,8 @@ |
798 | 798 | } |
799 | 799 | |
800 | 800 | function pageStats() { |
801 | | - global $wgOut, $wgLang, $wgArticle, $wgRequest; |
802 | | - global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax; |
| 801 | + global $wgOut, $wgLang, $wgArticle, $wgRequest, $wgUser; |
| 802 | + global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax, $wgTitle, $wgPageShowWatchingUsers; |
803 | 803 | |
804 | 804 | extract( $wgRequest->getValues( 'oldid', 'diff' ) ); |
805 | 805 | if ( ! $wgOut->isArticle() ) { return ''; } |
— | — | @@ -820,6 +820,17 @@ |
821 | 821 | $s .= $this->lastModified(); |
822 | 822 | } |
823 | 823 | |
| 824 | + if ($wgPageShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' )) { |
| 825 | + $dbr =& wfGetDB( DB_SLAVE ); |
| 826 | + extract( $dbr->tableNames( 'watchlist' ) ); |
| 827 | + $sql = "SELECT COUNT(*) AS n FROM $watchlist |
| 828 | + WHERE wl_title='" . $dbr->strencode($wgTitle->getDBKey()) . |
| 829 | + "' AND wl_namespace=" . $wgTitle->getNamespace() ; |
| 830 | + $res = $dbr->query( $sql, 'Skin::pageStats'); |
| 831 | + $x = $dbr->fetchObject( $res ); |
| 832 | + $s .= ' ' . wfMsg('number_of_watching_users_pageview', $x->n ); |
| 833 | + } |
| 834 | + |
824 | 835 | return $s . ' ' . $this->getCopyright(); |
825 | 836 | } |
826 | 837 | |
— | — | @@ -1101,7 +1112,10 @@ |
1102 | 1113 | return $wgEnableEmail && |
1103 | 1114 | $wgEnableUserEmail && |
1104 | 1115 | 0 != $wgUser->getID() && # show only to signed in users |
1105 | | - 0 != $id; # can only email non-anons |
| 1116 | + 0 != $id; # we can only email to non-anons .. |
| 1117 | +# '' != $id->getEmail() && # who must have an email address stored .. |
| 1118 | +# 0 != $id->getEmailauthenticationtimestamp() && # .. which is authenticated |
| 1119 | +# 1 != $wgUser->getOption('disablemail'); # and not disabled |
1106 | 1120 | } |
1107 | 1121 | |
1108 | 1122 | function emailUserLink() { |
— | — | @@ -1928,7 +1942,6 @@ |
1929 | 1943 | return '<a href="'.$url.'"'.$style.'>'.$text.'</a>'; |
1930 | 1944 | } |
1931 | 1945 | |
1932 | | - |
1933 | 1946 | /** |
1934 | 1947 | * This function is called by all recent changes variants, by the page history, |
1935 | 1948 | * and by the user contributions list. It is responsible for formatting edit |
Index: trunk/phase3/includes/templates/Userlogin.php |
— | — | @@ -94,7 +94,11 @@ |
95 | 95 | <p> |
96 | 96 | <?php $this->msgHtml( 'emailforlost' ) ?><br /> |
97 | 97 | <input tabindex='10' type='submit' name="wpMailmypassword" |
98 | | - value="<?php $this->msg('mailmypassword') ?>" /> |
| 98 | + value="<?php if ( $this->data['useemailauthent'] ) { |
| 99 | + $this->msg('mailmypasswordauthent') ?>" /> |
| 100 | + <?php } else { |
| 101 | + $this->msg('mailmypassword') ?>" /> |
| 102 | + <?php } ?> |
99 | 103 | </p> |
100 | 104 | </td> |
101 | 105 | </tr> |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -3,7 +3,112 @@ |
4 | 4 | Security reminder: MediaWiki does not require PHP's register_globals |
5 | 5 | setting since version 1.2.0. If you have it on, turn it *off* if you can. |
6 | 6 | |
| 7 | +== Version Enotif+Eauthent EN+EA v2.00/CVS, 14.12.2004 == |
| 8 | +written by Thomas Gries, Berlin and Markus Arndt, Munich |
7 | 9 | |
| 10 | +Executive summary for the impatient reader: |
| 11 | + |
| 12 | +Enotif adds e-mail notification to MediaWiki and sends e-mails |
| 13 | +to watching users when a watch-listed page or user_talk page is changed |
| 14 | +http://bugzilla.wikipedia.org/show_bug.cgi?id=454 |
| 15 | +Visit the complete documentation on http://meta.wikipedia.org/Enotif |
| 16 | + |
| 17 | +Eauthent is a mechanism to use a temporary one-time password cycle |
| 18 | +to check whether the email address a user has entered is a valid one. |
| 19 | +http://bugzilla.wikipedia.org/show_bug.cgi?id=866 |
| 20 | +Visit the complete documentation on http://meta.wikipedia.org/Eauthent |
| 21 | + |
| 22 | +The current patch has only been checked for (see DefaultSettings.php): |
| 23 | + |
| 24 | +- php mail() |
| 25 | + ( = not using PEAR:Mail() module --- I do not know anyone who uses that) |
| 26 | + $wgSMTP = false; |
| 27 | +- MySQL database |
| 28 | + ( = not using PostgreSQL --- I do not know anyone who uses that) |
| 29 | + $wgDBtype = "mysql"; |
| 30 | + $wgSearchType = "MyISAM"; |
| 31 | + |
| 32 | +- STILL TODO: |
| 33 | + NEW (newpageletter) and CORR (minoreditletter) markers needs |
| 34 | + corresponding "spacers" |
| 35 | + |
| 36 | +- table user_newtalk dropped; changes on usertalk pages and their |
| 37 | + notifications are now fully handled via existing table watchlist |
| 38 | + The user interface and behavious is unchanged to previous version. |
| 39 | +- updaters.inc for compatibility with older mediawiki tables: |
| 40 | + the conversion script converts existing user_newtalk entries |
| 41 | + watchlist table entries |
| 42 | + (user_newtalk) id ==> (watchlist) NS_USER_TALK:namefromId(id) timestamp=1 |
| 43 | +- minor bug fixes: |
| 44 | + updated marker now correctly shown on watchlist page |
| 45 | + watching users number display with enhanced RC view + RCUseModStyle |
| 46 | +- wfUrlencode() instead of rawurlencode() in enotif mails |
| 47 | +- duplicate enotif code moved from UserTalkUpdate.php and |
| 48 | + merged into UserMailer.php and using usermailer() solely |
| 49 | +- fixed an enotif mail text error for user names with spaces |
| 50 | +- fixed missing part for suppressing watching user number |
| 51 | + |
| 52 | +v1.36: |
| 53 | +magic watchlist shows and counts now only the content page, notwithstanding |
| 54 | +the content and talk page are stored separately in watchlist. |
| 55 | +* bug fixed: rawurlencode for pagetitles in enotif mails |
| 56 | +* bug fixed: link to userpages of anonymous user are correct now |
| 57 | + |
| 58 | +* Enotif v1.34 |
| 59 | + bugs fixed regarding missing $oldid parameter |
| 60 | + |
| 61 | +* v1.33 |
| 62 | +* Details: |
| 63 | + Implements almost all enotif options as user preferences. |
| 64 | + These are only shown on the user preference page, if they are globally |
| 65 | + enabled by the corresponding admin option in DefaultSettings.php. |
| 66 | + Added admin feature to let enotifs appear to come from the page editor. |
| 67 | + This facilitates automatic mail sorting and anti-spam filtering; feature was |
| 68 | + originally proposed by Nick Triantos, thank you ! |
| 69 | + Page editor's email address is however only shown, if this user enabled |
| 70 | + the option "reveal my email address" in user preferences. Otherwise, |
| 71 | + the enotifs appear to come from WikiAdmin as usual (tricky to program, |
| 72 | + but simply trust the algorithm. or look into UserMailer.php and |
| 73 | + UserTalkPage.php). |
| 74 | + |
| 75 | +* Changes from previous enotif versions |
| 76 | +* v1.31 is an improved version with many security and also cosmetic changes |
| 77 | + applied after two first reviews by Brion Vibber. v1.31 is basically the same as |
| 78 | + the older Enotif v1.30 and v1.22 versions. |
| 79 | + |
| 80 | + Added UseMod style for recent changes view so that only the most recent |
| 81 | + change of any page is listed. The (diff) and (hist) still allow to retrieve the |
| 82 | + older versions at users' discretion, but the RC view is much cleaner for |
| 83 | + trusted environments such as medium-size companies or family wikis. |
| 84 | + |
| 85 | +* Enotif v1.30 redesign after review by Brion Vibber 25.10.2003 |
| 86 | + |
| 87 | +* v1.22 "updated (since my last visit)" also shown for users without stored |
| 88 | + email address in preferences, so that they can see, what watched pages |
| 89 | + have changed. |
| 90 | +* show "updated (since my last visit)" markers in RC, history and watchlist |
| 91 | +* Systemvariables to suppress updated marker in all views |
| 92 | +* show number of watching users in RC and on bottom of articles in |
| 93 | + classic skin and in monobook skin |
| 94 | +* Systemvariables in DefaultSettings.php to enable or disable features |
| 95 | +* v1.21 now suppresses displaying the marker "updated (since my last visit)" |
| 96 | + in recent changes view for the older (already visited) versions of watched |
| 97 | + pages - i.e. page versions before the enotif was sent do not bear that |
| 98 | + marker any longer. |
| 99 | +* enotif mails come with a link to the diff view between current and last |
| 100 | + visited version of the watching user. |
| 101 | +*database structure is changed automatically when installing via the |
| 102 | + recommended way (starting index.php and re-using the old database name). |
| 103 | + run php /maintenance/update.php |
| 104 | + OR see /maintenance/archives/patch-email-notification.sql and apply the |
| 105 | + command |
| 106 | + ALTER TABLE watchlist |
| 107 | + ADD (wl_notificationtimestamp varchar(14) binary NOT NULL default '0'); |
| 108 | + manually to your database, which does not harm the non notification versions |
| 109 | + |
| 110 | +*adding a page x to the watchlist does automatically add a watch |
| 111 | + for the accompanying talk_page talk:x and vice versa; |
| 112 | + |
8 | 113 | == MediaWiki 1.4 BETA == |
9 | 114 | |
10 | 115 | [Not everything is 100% working in beta yet, the installer needs fixes still.] |
Index: trunk/phase3/languages/LanguageDe.php |
— | — | @@ -684,10 +684,13 @@ |
685 | 685 | "largefile" => "Bitte keine Bilder über 100 KByte hochladen.", |
686 | 686 | 'emptyfile' => "Die hochgeladene Datei ist leer. Der Grund kann ein Tippfehler im Dateinamen sein. Bitte kontrollieren Sie, ob Sie die Datei wirklich hochladen wollen.", |
687 | 687 | "successfulupload" => "Erfolgreich hochgeladen", |
688 | | -"fileuploaded" => "Die Datei \"$1\" wurde erfolgreich hochgeladen. Bitte |
689 | | -verwenden Sie diesen ($2) Link zur Beschreibungsseite und füllen Sie die |
690 | | -Informationen über die Datei aus, insbesondere seine Herkunft, von wem und wann es |
691 | | -gemacht wurde und besondere Angaben zum Copyright, falls notwendig.", |
| 688 | +"fileuploaded" => "Die Datei \"$1\" wurde erfolgreich hochgeladen. |
| 689 | +Bitte verwenden Sie diesen ($2) Link zur Beschreibungsseite und füllen Sie die Informationen über die Datei |
| 690 | + aus, insbesondere seine Herkunft, von wem und wann es |
| 691 | + gemacht wurde und besondere Angaben zum Copyright, falls notwendig. |
| 692 | + Falls es sich um ein Bild handelte, so können Sie mit |
| 693 | + <tt><nowiki>[[Image:$1|thumb|Description]]</nowiki></tt> ein Vorschaubild |
| 694 | + auf der Seite erzeugen lassen.", |
692 | 695 | "uploadwarning" => "Warnung", |
693 | 696 | "savefile" => "Datei speichern", |
694 | 697 | "uploadedimage" => "\"$1\" hochgeladen", |
Index: trunk/phase3/languages/Language.php |
— | — | @@ -51,14 +51,35 @@ |
52 | 52 | } |
53 | 53 | |
54 | 54 | /* private */ $wgDefaultUserOptionsEn = array( |
55 | | - 'quickbar' => 1, 'underline' => 1, 'hover' => 1, |
56 | | - 'cols' => 80, 'rows' => 25, 'searchlimit' => 20, |
57 | | - 'contextlines' => 5, 'contextchars' => 50, |
58 | | - 'skin' => $wgDefaultSkin, 'math' => 1, 'rcdays' => 7, 'rclimit' => 50, |
59 | | - 'highlightbroken' => 1, 'stubthreshold' => 0, |
60 | | - 'previewontop' => 1, 'editsection'=>1,'editsectiononrightclick'=>0, 'showtoc'=>1, |
61 | | - 'showtoolbar' =>1, |
62 | | - 'date' => 0, 'imagesize' => 2 |
| 55 | + 'quickbar' => 1, |
| 56 | + 'underline' => 1, |
| 57 | + 'hover' => 1, |
| 58 | + 'cols' => 80, |
| 59 | + 'rows' => 25, |
| 60 | + 'searchlimit' => 20, |
| 61 | + 'contextlines' => 5, |
| 62 | + 'contextchars' => 50, |
| 63 | + 'skin' => $wgDefaultSkin, |
| 64 | + 'math' => 1, |
| 65 | + 'rcdays' => 7, |
| 66 | + 'rclimit' => 50, |
| 67 | + 'highlightbroken' => 1, |
| 68 | + 'stubthreshold' => 0, |
| 69 | + 'previewontop' => 1, |
| 70 | + 'editsection' => 1, |
| 71 | + 'editsectiononrightclick'=> 0, |
| 72 | + 'showtoc' => 1, |
| 73 | + 'showtoolbar' => 1, |
| 74 | + 'date' => 0, |
| 75 | + 'imagesize' => 2, |
| 76 | + 'rememberpassword' => 0, |
| 77 | + 'enotifwatchlistpages' => 1, |
| 78 | + 'enotifusertalkpages' => 1, |
| 79 | + 'enotifminoredits' => 0, |
| 80 | + 'enotifrevealaddr' => 0, |
| 81 | + 'shownumberswatching' => 1, |
| 82 | + 'rcusemodstyle' => 1, |
| 83 | + 'showupdated' => 1 |
63 | 84 | ); |
64 | 85 | |
65 | 86 | /* private */ $wgQuickbarSettingsEn = array( |
— | — | @@ -127,6 +148,13 @@ |
128 | 149 | 'previewontop', |
129 | 150 | 'previewonfirst', |
130 | 151 | 'nocache', |
| 152 | + 'enotifwatchlistpages', |
| 153 | + 'enotifusertalkpages', |
| 154 | + 'enotifminoredits', |
| 155 | + 'enotifrevealaddr', |
| 156 | + 'shownumberswatching', |
| 157 | + 'rcusemodstyle', |
| 158 | + 'showupdated', |
131 | 159 | ); |
132 | 160 | |
133 | 161 | /* private */ $wgBookstoreListEn = array( |
— | — | @@ -229,11 +257,11 @@ |
230 | 258 | 'tog-hideminor' => 'Hide minor edits in recent changes', |
231 | 259 | 'tog-usenewrc' => 'Enhanced recent changes (not for all browsers)', |
232 | 260 | 'tog-numberheadings' => 'Auto-number headings', |
233 | | -'tog-showtoolbar'=>'Show edit toolbar', |
| 261 | +'tog-showtoolbar' => 'Show edit toolbar', |
234 | 262 | 'tog-editondblclick' => 'Edit pages on double click (JavaScript)', |
235 | | -'tog-editsection'=>'Enable section editing via [edit] links', |
236 | | -'tog-editsectiononrightclick'=>'Enable section editing by right clicking<br /> on section titles (JavaScript)', |
237 | | -'tog-showtoc'=>'Show table of contents<br />(for pages with more than 3 headings)', |
| 263 | +'tog-editsection' => 'Enable section editing via [edit] links', |
| 264 | +'tog-editsectiononrightclick' => 'Enable section editing by right clicking<br /> on section titles (JavaScript)', |
| 265 | +'tog-showtoc' => 'Show table of contents<br />(for pages with more than 3 headings)', |
238 | 266 | 'tog-rememberpassword' => 'Remember password across sessions', |
239 | 267 | 'tog-editwidth' => 'Edit box has full width', |
240 | 268 | 'tog-watchdefault' => 'Add pages you edit to your watchlist', |
— | — | @@ -241,6 +269,13 @@ |
242 | 270 | 'tog-previewontop' => 'Show preview before edit box and not after it', |
243 | 271 | 'tog-previewonfirst' => 'Show preview on first edit', |
244 | 272 | 'tog-nocache' => 'Disable page caching', |
| 273 | +'tog-enotifwatchlistpages' => 'Send me an email on page changes (remark: existing notification flags need to be cleared manually in the watchlist)', |
| 274 | +'tog-enotifusertalkpages' => 'Send me an email when my user talk page is changed (remark: existing notification flags need to be cleared manually in the watchlist)', |
| 275 | +'tog-enotifminoredits' => 'Send me an email also for minor edits of pages (which usually do not trigger notification mails)', |
| 276 | +'tog-enotifrevealaddr' => 'Reveal my email address in notification mails (when I change a page, it allows watching users to reply quickly to me)', |
| 277 | +'tog-shownumberswatching' => 'Show the number of watching users (in recent changes view, watchlist and article page footers)', |
| 278 | +'tog-rcusemodstyle' => 'Show recent changes in UseMod style: only the most recent change of any page is listed.', |
| 279 | +'tog-showupdated' => 'Show update marker ', |
245 | 280 | |
246 | 281 | # dates |
247 | 282 | 'sunday' => 'Sunday', |
— | — | @@ -494,11 +529,11 @@ |
495 | 530 | # Login and logout pages |
496 | 531 | # |
497 | 532 | "logouttitle" => 'User logout', |
498 | | -"logouttext" => "You are now logged out. |
| 533 | +"logouttext" => "You are now logged out.<br> |
499 | 534 | You can continue to use {{SITENAME}} anonymously, or you can log in |
500 | 535 | again as the same or as a different user. Note that some pages may |
501 | 536 | continue to be displayed as if you were still logged in, until you clear |
502 | | -your browser cache\n", |
| 537 | +your browser cache.\n", |
503 | 538 | |
504 | 539 | 'welcomecreation' => "== Welcome, $1! == |
505 | 540 | |
— | — | @@ -523,13 +558,17 @@ |
524 | 559 | 'createaccountmail' => 'by email', |
525 | 560 | 'badretype' => 'The passwords you entered do not match.', |
526 | 561 | 'userexists' => 'The user name you entered is already in use. Please choose a different name.', |
527 | | -'youremail' => 'Your email*', |
| 562 | +'youremail' => 'Your email**', |
528 | 563 | 'yourrealname' => 'Your real name*', |
529 | 564 | 'yourlanguage' => 'Interface language', |
530 | 565 | 'yourvariant' => 'Language variant', |
531 | 566 | 'yournick' => 'Your nickname (for signatures)', |
532 | | -'emailforlost' => "Fields marked with a star (*) are optional. Storing an email address enables people to contact you through the website without you having to reveal your |
| 567 | +'emailforlost' => "Fields marked with stars (*, **) are optional. Storing an email address enables people to contact you through the website without you having to reveal your |
533 | 568 | email address to them, and it can be used to send you a new password if you forget it.<br /><br />Your real name, if you choose to provide it, will be used for giving you attribution for your work.", |
| 569 | +'prefs-help-email' => '** <strong>Email</strong> (optional): Enables others to contact you through your user or user_talk page without the need of revealing your |
| 570 | +email address. It also allows the wiki to sent you a temporary password in case you forgot your current one.', |
| 571 | +'prefs-help-email-enotif' => 'This address is also used to send you email notifications if you enabled the options.', |
| 572 | +'prefs-help-realname' => '* <strong>Real name</strong> (optional): if you choose to provide it this will be used for giving you attribution for your work.', |
534 | 573 | 'prefs-help-userdata' => '* <strong>Real name</strong> (optional): if you choose to provide it this will be used for giving you attribution for your work.<br /> |
535 | 574 | * <strong>Email</strong> (optional): Enables people to contact you through the website without you having to reveal your |
536 | 575 | email address to them, and it can be used to send you a new password if you forget it.', |
— | — | @@ -542,20 +581,40 @@ |
543 | 582 | 'nosuchuser' => "There is no user by the name \"$1\". |
544 | 583 | Check your spelling, or use the form below to create a new user account.", |
545 | 584 | 'nosuchusershort' => "There is no user by the name \"$1\". Check your spelling.", |
546 | | -'wrongpassword' => 'The password you entered is incorrect. Please try again.', |
547 | | -'mailmypassword' => 'Mail me a new password', |
548 | | -'passwordremindertitle' => "Password reminder from {{SITENAME}}", |
549 | | -'passwordremindertext' => "Someone (probably you, from IP address $1) |
550 | | -requested that we send you a new {{SITENAME}} login password. |
551 | | -The password for user \"$2\" is now \"$3\". |
552 | | -You should log in and change your password now.", |
| 585 | +'wrongpassword' => 'The password you entered is incorrect (or missing). Please try again.', |
| 586 | +'mailmypassword' => 'Mail me a temporary password |
| 587 | +because I forgot my password', |
| 588 | +'mailmypasswordauthent' => 'Mail me a temporary password |
| 589 | +because I forgot my password or |
| 590 | +for authentication of my email address', |
| 591 | +'passwordremindermailsubject' => "Email address authentication and temporary login password from {{SITENAME}}", |
| 592 | +'passwordremindermailbody' => "Someone, probably you from IP address $1, |
| 593 | +requested that we send you a temporary one-time login password for {{SITENAME}}. |
| 594 | + |
| 595 | +This mail is also be sent for the purpose of authentication of your email address. |
| 596 | +The password for user \"$2\" is now \"$4\". |
| 597 | + |
| 598 | +You can now log in with this temporary password, which is valid for only one login. |
| 599 | +You may wish to keep using your old password if you remember it or to set a new one. |
| 600 | + |
| 601 | +{{SERVER}}{{localurl:Special:Userlogin|wpName=$3&wpPassword=$4&returnto=Special:Preferences}}", |
553 | 602 | 'noemail' => "There is no e-mail address recorded for user \"$1\".", |
554 | | -'passwordsent' => "A new password has been sent to the e-mail address |
| 603 | +'passwordsent' => "A temporary password has been sent to the e-mail address |
555 | 604 | registered for \"$1\". |
556 | 605 | Please log in again after you receive it.", |
| 606 | +'passwordsentforemailauthentication' |
| 607 | + => "A temporary password has been sent to the e-mail address newly |
| 608 | +registered for \"$1\". |
| 609 | +Please re-login with that for authentication purposes.", |
557 | 610 | 'loginend' => ' ', |
558 | 611 | 'mailerror' => "Error sending mail: $1", |
559 | 612 | 'acct_creation_throttle_hit' => 'Sorry, you have already created $1 accounts. You can\'t make any more.', |
| 613 | +'emailauthenticated' => 'Your email address was authenticated on $1.', |
| 614 | +'emailnotauthenticated' => 'Your email address is <strong>not yet authenticated</strong> and the advanced email features are disabled until authentication <strong>(d.u.a.)</strong>.<br> |
| 615 | +To authenticate, please login in with the temporary password which has been mailed to you, or request a new one on the login page.', |
| 616 | +'invalidemailaddress' => 'The email address cannot be accepted as it appears to have an invalid format. Please enter a well-formatted address or empty that field.', |
| 617 | +'disableduntilauthent' => '<strong>(d.u.a.)</strong>', |
| 618 | +'disablednoemail' => '<strong>(disabled; no email address)</strong>', |
560 | 619 | |
561 | 620 | # Edit page toolbar |
562 | 621 | 'bold_sample'=>'Bold text', |
— | — | @@ -586,7 +645,7 @@ |
587 | 646 | # |
588 | 647 | 'summary' => 'Summary', |
589 | 648 | 'subject' => 'Subject/headline', |
590 | | -'minoredit' => 'This is a minor edit', |
| 649 | +'minoredit' => 'This is a minor edit.', |
591 | 650 | 'watchthis' => 'Watch this page', |
592 | 651 | 'savearticle' => 'Save page', |
593 | 652 | 'preview' => 'Preview', |
— | — | @@ -866,6 +925,8 @@ |
867 | 926 | 'minoreditletter' => 'm', |
868 | 927 | 'newpageletter' => 'N', |
869 | 928 | 'sectionlink' => '→', |
| 929 | +'number_of_watching_users_RCview' => '[$1]', |
| 930 | +'number_of_watching_users_pageview' => '[$1 watching user/s]', |
870 | 931 | |
871 | 932 | # Upload |
872 | 933 | # |
— | — | @@ -1145,9 +1206,8 @@ |
1146 | 1207 | 'removechecked' => 'Remove checked items from watchlist', |
1147 | 1208 | 'watchlistcontains' => "Your watchlist contains $1 pages.", |
1148 | 1209 | 'watcheditlist' => 'Here\'s an alphabetical list of your |
1149 | | -watched pages. Check the boxes of pages you want to remove |
1150 | | -from your watchlist and click the \'remove checked\' button |
1151 | | -at the bottom of the screen.', |
| 1210 | +watched content pages. Check the boxes of pages you want to remove from your watchlist and click the \'remove checked\' button |
| 1211 | +at the bottom of the screen (deleting a content page also deletes the accompanying talk page and vice versa).', |
1152 | 1212 | 'removingchecked' => 'Removing requested items from watchlist...', |
1153 | 1213 | 'couldntremove' => "Couldn't remove item '$1'...", |
1154 | 1214 | 'iteminvalidname' => "Problem with item '$1', invalid name...", |
— | — | @@ -1155,7 +1215,49 @@ |
1156 | 1216 | 'wlshowlast' => "Show last $1 hours $2 days $3", |
1157 | 1217 | 'wlsaved' => 'This is a saved version of your watchlist.', |
1158 | 1218 | |
| 1219 | +'updatedmarker' => '<span class=\'updatedmarker\'> updated (since my last visit) </span>', |
1159 | 1220 | |
| 1221 | +'email_notification_mailer' => '{{SITENAME}} Notification Mailer', |
| 1222 | +'email_notification_infotext' => ' |
| 1223 | +<strong>Email Notification</strong><p> |
| 1224 | +<form action=\'{{localurl:Special:Watchlist|action=submit&magic=yes}}\' method=\'post\'> |
| 1225 | +<ul> |
| 1226 | +<li>You will be notified by email when someone changes a page which is listed in your watchlist.</li> |
| 1227 | +<li>A flag is set so that you receive only one email on the first change.</li> |
| 1228 | +<li>Your own edits do <b>not</b> trigger the sending of notifications. |
| 1229 | +<li>{{MediaWiki:updatedmarker}} means that the <b><i>page has changed since your last visit and that a notification mail has been sent to you.</i></b>.</li> |
| 1230 | +<li>The flag is automatically cleared when you visit such pages.</li> |
| 1231 | +<li> Alternatively, you can reset all flags at once by clicking on <input type="submit" name="dummy" value=\'Reset all notification flags (set their status to "visited")\'><input type="hidden" name="reset" value="all"></form></li> |
| 1232 | +</ul> |
| 1233 | +<hr>', |
| 1234 | +'email_notification_newpagetext'=> 'This is a new page.', |
| 1235 | +'email_notification_to' => '$WATCHINGUSERNAME_QP <$WATCHINGUSEREMAILADDR>', |
| 1236 | +'email_notification_subject' => '{{SITENAME}} page $PAGETITLE_QP has been changed by $PAGEEDITOR_QP', |
| 1237 | +'email_notification_lastvisitedrevisiontext' => 'See {{SERVER}}{{localurl:$PAGETITLE_RAWURL|diff=0&oldid=$OLDID}} for all changes since your last visit.', |
| 1238 | +'email_notification_body' => 'Dear $WATCHINGUSERNAME, |
| 1239 | + |
| 1240 | +the {{SITENAME}} page $PAGETITLE has been changed on $PAGEEDITDATE by $PAGEEDITOR, |
| 1241 | +see {{SERVER}}{{localurl:$PAGETITLE_RAWURL}} for the current version. |
| 1242 | + |
| 1243 | +$NEWPAGE |
| 1244 | + |
| 1245 | +Editor\'s summary: $PAGESUMMARY $PAGEMINOREDIT |
| 1246 | +Contact the editor: |
| 1247 | +mail {{SERVER}}{{localurl:Special:Emailuser|target=$PAGEEDITOR_RAWURL}} |
| 1248 | +wiki {{SERVER}}{{localurl:User:$PAGEEDITOR_RAWURL}} |
| 1249 | + |
| 1250 | +There will be no other notifications in case of further changes unless you visit this page. |
| 1251 | +You could also reset the notification flags for all your watched pages on your watchlist. |
| 1252 | + |
| 1253 | + Your friendly {{SITENAME}} notification system |
| 1254 | + |
| 1255 | +-- |
| 1256 | +To change your watchlist settings, visit |
| 1257 | +{{SERVER}}{{localurl:Special:Watchlist|magic=yes}} |
| 1258 | + |
| 1259 | +Feedback and further assistance: |
| 1260 | +{{SERVER}}{{localurl:WikiHelpdesk}}', |
| 1261 | + |
1160 | 1262 | # Delete/protect/revert |
1161 | 1263 | # |
1162 | 1264 | 'deletepage' => 'Delete page', |
— | — | @@ -1772,10 +1874,13 @@ |
1773 | 1875 | return wfMsg($wgWeekdayNamesEn[$key-1]); |
1774 | 1876 | } |
1775 | 1877 | |
1776 | | - function userAdjust( $ts ) { |
| 1878 | + function userAdjust( $ts, $tz = false ) { |
1777 | 1879 | global $wgUser, $wgLocalTZoffset; |
1778 | 1880 | |
| 1881 | + if (!$tz) { |
1779 | 1882 | $tz = $wgUser->getOption( 'timecorrection' ); |
| 1883 | + } |
| 1884 | + |
1780 | 1885 | if ( $tz === '' ) { |
1781 | 1886 | $hrDiff = isset( $wgLocalTZoffset ) ? $wgLocalTZoffset : 0; |
1782 | 1887 | $minDiff = 0; |
— | — | @@ -1798,11 +1903,13 @@ |
1799 | 1904 | return date( 'YmdHis', $t ); |
1800 | 1905 | } |
1801 | 1906 | |
1802 | | - function date( $ts, $adj = false, $format = MW_DATE_USER_FORMAT ) { |
| 1907 | + function date( $ts, $adj = false, $format = MW_DATE_USER_FORMAT, $timecorrection = false ) { |
1803 | 1908 | global $wgAmericanDates, $wgUser, $wgUseDynamicDates; |
1804 | 1909 | |
1805 | 1910 | $ts=wfTimestamp(TS_MW,$ts); |
1806 | | - if ( $adj ) { $ts = $this->userAdjust( $ts ); } |
| 1911 | + |
| 1912 | + if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); } |
| 1913 | + |
1807 | 1914 | if ( $wgUseDynamicDates ) { |
1808 | 1915 | if ( $format == MW_DATE_USER_FORMAT ) { |
1809 | 1916 | $datePreference = $wgUser->getOption( 'date' ); |
— | — | @@ -1828,10 +1935,10 @@ |
1829 | 1936 | } |
1830 | 1937 | } |
1831 | 1938 | |
1832 | | - function time( $ts, $adj = false, $seconds = false ) { |
| 1939 | + function time( $ts, $adj = false, $seconds = false, $timecorrection = false ) { |
1833 | 1940 | $ts=wfTimestamp(TS_MW,$ts); |
1834 | 1941 | |
1835 | | - if ( $adj ) { $ts = $this->userAdjust( $ts ); } |
| 1942 | + if ( $adj ) { $ts = $this->userAdjust( $ts, $timecorrection ); } |
1836 | 1943 | |
1837 | 1944 | $t = substr( $ts, 8, 2 ) . ':' . substr( $ts, 10, 2 ); |
1838 | 1945 | if ( $seconds ) { |
— | — | @@ -1840,10 +1947,14 @@ |
1841 | 1948 | return $this->formatNum( $t ); |
1842 | 1949 | } |
1843 | 1950 | |
1844 | | - function timeanddate( $ts, $adj = false, $format = MW_DATE_USER_FORMAT ) { |
| 1951 | + function timeanddate( $ts, $adj = false, $format = MW_DATE_USER_FORMAT, $timecorrection = false, $dateandtime = false) { |
1845 | 1952 | $ts=wfTimestamp(TS_MW,$ts); |
1846 | | - |
1847 | | - return $this->time( $ts, $adj ) . ', ' . $this->date( $ts, $adj, $format ); |
| 1953 | + if ($dateandtime) { |
| 1954 | + $ret = $this->date( $ts, $adj, $format, $timecorrection ) . ', ' . $this->time( $ts, $adj, false, $timecorrection ); |
| 1955 | + } else { |
| 1956 | + $ret = $this->time( $ts, $adj, false, $timecorrection ) . ', ' . $this->date( $ts, $adj, $format, $timecorrection ); |
| 1957 | + } |
| 1958 | + return $ret; |
1848 | 1959 | } |
1849 | 1960 | |
1850 | 1961 | function rfc1123( $ts ) { |