Index: branches/robchurch/newtalk/maintenance/archives/patch-fix-newtalk.sql |
— | — | @@ -0,0 +1,9 @@ |
| 2 | +-- Alters columns in `user_newtalk` to be nullable and |
| 3 | +-- drops existing indices in favour of a single UNIQUE |
| 4 | +-- index |
| 5 | +ALTER TABLE /*wgDBprefix*/user_newtalk |
| 6 | +DROP INDEX `user_id`, |
| 7 | +DROP INDEX `user_ip`, |
| 8 | +CHANGE `user_id` `user_id` INT(5) NULL, |
| 9 | +CHANGE `user_ip` `user_ip` VARCHAR(40) NULL, |
| 10 | +ADD UNIQUE( `user_id`, `user_ip` ) |
Property changes on: branches/robchurch/newtalk/maintenance/archives/patch-fix-newtalk.sql |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 11 | + native |
Index: branches/robchurch/newtalk/maintenance/updaters.inc |
— | — | @@ -932,6 +932,9 @@ |
933 | 933 | |
934 | 934 | do_backlinking_indices_update(); flush(); |
935 | 935 | |
| 936 | + fix_newtalk(); |
| 937 | + flush(); |
| 938 | + |
936 | 939 | do_restrictions_update(); flush (); |
937 | 940 | |
938 | 941 | echo "Deleting old default messages (this may take a long time!)..."; flush(); |
— | — | @@ -956,6 +959,20 @@ |
957 | 960 | } |
958 | 961 | } |
959 | 962 | |
| 963 | +/** |
| 964 | + * Fixes up some columns and indices in `user_newtalk` |
| 965 | + */ |
| 966 | +function fix_newtalk() { |
| 967 | + global $wgDatabase; |
| 968 | + if( $wgDatabase->indexExists( 'user_newtalk', 'user_id' ) ) { |
| 969 | + echo( "Fixing up `user_newtalk`..." ); |
| 970 | + $wgDatabase->sourceFile( archive( 'patch-fix-newtalk.sql' ) ); |
| 971 | + echo( "done.\n" ); |
| 972 | + } else { |
| 973 | + echo( "`user_newtalk` seems to be fixed up.\n" ); |
| 974 | + } |
| 975 | +} |
| 976 | + |
960 | 977 | function do_restrictions_update() { |
961 | 978 | # Adding page_restrictions table, obsoleting page.page_restrictions. |
962 | 979 | # Migrating old restrictions to new table |
Index: branches/robchurch/newtalk/includes/User.php |
— | — | @@ -1175,31 +1175,16 @@ |
1176 | 1176 | return str_replace( ' ', '_', $this->getName() ); |
1177 | 1177 | } |
1178 | 1178 | |
1179 | | - function getNewtalk() { |
| 1179 | + /** |
| 1180 | + * Is the "new messages" flag set for this user? |
| 1181 | + * |
| 1182 | + * @return bool |
| 1183 | + */ |
| 1184 | + public function getNewtalk() { |
1180 | 1185 | $this->load(); |
1181 | | - |
1182 | | - # Load the newtalk status if it is unloaded (mNewtalk=-1) |
1183 | | - if( $this->mNewtalk === -1 ) { |
1184 | | - $this->mNewtalk = false; # reset talk page status |
1185 | | - |
1186 | | - # Check memcached separately for anons, who have no |
1187 | | - # entire User object stored in there. |
1188 | | - if( !$this->mId ) { |
1189 | | - global $wgMemc; |
1190 | | - $key = wfMemcKey( 'newtalk', 'ip', $this->getName() ); |
1191 | | - $newtalk = $wgMemc->get( $key ); |
1192 | | - if( $newtalk != "" ) { |
1193 | | - $this->mNewtalk = (bool)$newtalk; |
1194 | | - } else { |
1195 | | - $this->mNewtalk = $this->checkNewtalk( 'user_ip', $this->getName() ); |
1196 | | - $wgMemc->set( $key, (int)$this->mNewtalk, time() + 1800 ); |
1197 | | - } |
1198 | | - } else { |
1199 | | - $this->mNewtalk = $this->checkNewtalk( 'user_id', $this->mId ); |
1200 | | - } |
1201 | | - } |
1202 | | - |
1203 | | - return (bool)$this->mNewtalk; |
| 1186 | + if( $this->mNewtalk === -1 ) |
| 1187 | + $this->mNewtalk = NewTalk::get( $this ); |
| 1188 | + return $this->mNewtalk; |
1204 | 1189 | } |
1205 | 1190 | |
1206 | 1191 | /** |
— | — | @@ -1217,108 +1202,36 @@ |
1218 | 1203 | return array(array("wiki" => wfWikiID(), "link" => $utp->getLocalURL())); |
1219 | 1204 | } |
1220 | 1205 | |
1221 | | - |
1222 | 1206 | /** |
1223 | | - * Perform a user_newtalk check on current slaves; if the memcached data |
1224 | | - * is funky we don't want newtalk state to get stuck on save, as that's |
1225 | | - * damn annoying. |
| 1207 | + * Set the "new messages" flag for this user |
1226 | 1208 | * |
1227 | | - * @param string $field |
1228 | | - * @param mixed $id |
1229 | | - * @return bool |
1230 | | - * @private |
| 1209 | + * @param bool $set Flag state |
1231 | 1210 | */ |
1232 | | - function checkNewtalk( $field, $id ) { |
1233 | | - $dbr = wfGetDB( DB_SLAVE ); |
1234 | | - $ok = $dbr->selectField( 'user_newtalk', $field, |
1235 | | - array( $field => $id ), __METHOD__ ); |
1236 | | - return $ok !== false; |
1237 | | - } |
1238 | | - |
1239 | | - /** |
1240 | | - * Add or update the |
1241 | | - * @param string $field |
1242 | | - * @param mixed $id |
1243 | | - * @private |
1244 | | - */ |
1245 | | - function updateNewtalk( $field, $id ) { |
1246 | | - if( $this->checkNewtalk( $field, $id ) ) { |
1247 | | - wfDebug( __METHOD__." already set ($field, $id), ignoring\n" ); |
1248 | | - return false; |
| 1211 | + public function setNewtalk( $set = true ) { |
| 1212 | + if( !$set ) { |
| 1213 | + $this->deleteNewtalk(); |
| 1214 | + } elseif( !wfReadOnly() ) { |
| 1215 | + $this->load(); |
| 1216 | + $this->mNewtalk = true; |
| 1217 | + NewTalk::set( $this ); |
| 1218 | + $this->addWatch( $this->getTalkPage() ); |
| 1219 | + $this->invalidateCache(); |
1249 | 1220 | } |
1250 | | - $dbw = wfGetDB( DB_MASTER ); |
1251 | | - $dbw->insert( 'user_newtalk', |
1252 | | - array( $field => $id ), |
1253 | | - __METHOD__, |
1254 | | - 'IGNORE' ); |
1255 | | - wfDebug( __METHOD__.": set on ($field, $id)\n" ); |
1256 | | - return true; |
1257 | 1221 | } |
1258 | | - |
| 1222 | + |
1259 | 1223 | /** |
1260 | | - * Clear the new messages flag for the given user |
1261 | | - * @param string $field |
1262 | | - * @param mixed $id |
1263 | | - * @private |
| 1224 | + * Unset the "new messages" flag for this user |
1264 | 1225 | */ |
1265 | | - function deleteNewtalk( $field, $id ) { |
1266 | | - if( !$this->checkNewtalk( $field, $id ) ) { |
1267 | | - wfDebug( __METHOD__.": already gone ($field, $id), ignoring\n" ); |
1268 | | - return false; |
| 1226 | + public function deleteNewtalk() { |
| 1227 | + if( !wfReadOnly() ) { |
| 1228 | + $this->load(); |
| 1229 | + $this->mNewtalk = false; |
| 1230 | + NewTalk::remove( $this ); |
| 1231 | + $this->invalidateCache(); |
1269 | 1232 | } |
1270 | | - $dbw = wfGetDB( DB_MASTER ); |
1271 | | - $dbw->delete( 'user_newtalk', |
1272 | | - array( $field => $id ), |
1273 | | - __METHOD__ ); |
1274 | | - wfDebug( __METHOD__.": killed on ($field, $id)\n" ); |
1275 | | - return true; |
1276 | 1233 | } |
1277 | 1234 | |
1278 | 1235 | /** |
1279 | | - * Update the 'You have new messages!' status. |
1280 | | - * @param bool $val |
1281 | | - */ |
1282 | | - function setNewtalk( $val ) { |
1283 | | - if( wfReadOnly() ) { |
1284 | | - return; |
1285 | | - } |
1286 | | - |
1287 | | - $this->load(); |
1288 | | - $this->mNewtalk = $val; |
1289 | | - |
1290 | | - if( $this->isAnon() ) { |
1291 | | - $field = 'user_ip'; |
1292 | | - $id = $this->getName(); |
1293 | | - } else { |
1294 | | - $field = 'user_id'; |
1295 | | - $id = $this->getId(); |
1296 | | - } |
1297 | | - |
1298 | | - if( $val ) { |
1299 | | - $changed = $this->updateNewtalk( $field, $id ); |
1300 | | - } else { |
1301 | | - $changed = $this->deleteNewtalk( $field, $id ); |
1302 | | - } |
1303 | | - |
1304 | | - if( $changed ) { |
1305 | | - if( $this->isAnon() ) { |
1306 | | - // Anons have a separate memcached space, since |
1307 | | - // user records aren't kept for them. |
1308 | | - global $wgMemc; |
1309 | | - $key = wfMemcKey( 'newtalk', 'ip', $val ); |
1310 | | - $wgMemc->set( $key, $val ? 1 : 0 ); |
1311 | | - } else { |
1312 | | - if( $val ) { |
1313 | | - // Make sure the user page is watched, so a notification |
1314 | | - // will be sent out if enabled. |
1315 | | - $this->addWatch( $this->getTalkPage() ); |
1316 | | - } |
1317 | | - } |
1318 | | - $this->invalidateCache(); |
1319 | | - } |
1320 | | - } |
1321 | | - |
1322 | | - /** |
1323 | 1236 | * Generate a current or new-future timestamp to be stored in the |
1324 | 1237 | * user_touched field when we update things. |
1325 | 1238 | */ |
Index: branches/robchurch/newtalk/includes/AutoLoader.php |
— | — | @@ -235,6 +235,7 @@ |
236 | 236 | 'StringUtils' => 'includes/StringUtils.php', |
237 | 237 | 'Title' => 'includes/Title.php', |
238 | 238 | 'User' => 'includes/User.php', |
| 239 | + 'NewTalk' => 'includes/NewTalk.php', |
239 | 240 | 'MailAddress' => 'includes/UserMailer.php', |
240 | 241 | 'EmailNotification' => 'includes/UserMailer.php', |
241 | 242 | 'WatchedItem' => 'includes/WatchedItem.php', |
Index: branches/robchurch/newtalk/includes/NewTalk.php |
— | — | @@ -0,0 +1,136 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Functions for managing "new messages" status |
| 6 | + * |
| 7 | + * @addtogroup User |
| 8 | + * @author Rob Church <robchur@gmail.com> |
| 9 | + */ |
| 10 | +class NewTalk { |
| 11 | + |
| 12 | + /** |
| 13 | + * Status flag constants |
| 14 | + */ |
| 15 | + const FLAG_SET = 'set'; |
| 16 | + const FLAG_UNSET = 'unset'; |
| 17 | + |
| 18 | + /** |
| 19 | + * Is the "new messages" flag set for a given user? |
| 20 | + * |
| 21 | + * @param User $user User to check status for |
| 22 | + * @return bool |
| 23 | + */ |
| 24 | + public static function get( User $user ) { |
| 25 | + global $wgMemc; |
| 26 | + wfProfileIn( __METHOD__ ); |
| 27 | + |
| 28 | + # Attempt to read from object cache |
| 29 | + $k = self::getCacheKey( $user ); |
| 30 | + if( ( $c = $wgMemc->get( $k ) ) !== false ) { |
| 31 | + wfDebugLog( 'newtalk', 'Got `newtalk` flag for user `' . $user->getName() . '` from cache' ); |
| 32 | + wfProfileOut( __METHOD__ ); |
| 33 | + return $c == self::FLAG_SET; |
| 34 | + } |
| 35 | + |
| 36 | + # Fall back to database |
| 37 | + list( $field, $value ) = self::getLookupConds( $user ); |
| 38 | + $set = self::getFromDB( $field, $value ); |
| 39 | + |
| 40 | + # Stash the value back in the object cache |
| 41 | + $c = $set ? self::FLAG_SET : self::FLAG_UNSET; |
| 42 | + $wgMemc->set( $k, $c, time() + 1800 ); |
| 43 | + |
| 44 | + # We're done |
| 45 | + wfDebugLog( 'newtalk', 'Got `newtalk` flag for user `' . $user->getName() . '` from database' ); |
| 46 | + wfProfileOut( __METHOD__ ); |
| 47 | + return $set; |
| 48 | + } |
| 49 | + |
| 50 | + /** |
| 51 | + * Set the "new messages" flag for a given user |
| 52 | + * |
| 53 | + * @param User $user User to update status for |
| 54 | + */ |
| 55 | + public static function set( User $user ) { |
| 56 | + global $wgMemc; |
| 57 | + wfProfileIn( __METHOD__ ); |
| 58 | + |
| 59 | + # Add to database |
| 60 | + $dbw = wfGetDB( DB_MASTER ); |
| 61 | + list( $field, $value ) = self::getLookupConds( $user ); |
| 62 | + $dbw->insert( 'user_newtalk', array( $field => $value ), __METHOD__, 'IGNORE' ); |
| 63 | + |
| 64 | + # Update object cache |
| 65 | + $wgMemc->set( self::getCacheKey( $user ), self::FLAG_SET, time() + 1800 ); |
| 66 | + |
| 67 | + # We're done |
| 68 | + wfDebugLog( 'newtalk', 'Set `newtalk` flag for user `' . $user->getName() . '`' ); |
| 69 | + wfProfileOut( __METHOD__ ); |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Unset the "new messages" flag for a given user |
| 74 | + * |
| 75 | + * @param User $user User to update status for |
| 76 | + */ |
| 77 | + public static function remove( User $user ) { |
| 78 | + global $wgMemc; |
| 79 | + wfProfileIn( __METHOD__ ); |
| 80 | + |
| 81 | + # Remove from database |
| 82 | + $dbw = wfGetDB( DB_MASTER ); |
| 83 | + list( $field, $value ) = self::getLookupConds( $user ); |
| 84 | + $dbw->delete( 'user_newtalk', array( $field => $value ), __METHOD__ ); |
| 85 | + |
| 86 | + # Update object cache |
| 87 | + $wgMemc->set( self::getCacheKey( $user ), self::FLAG_UNSET, time() + 1800 ); |
| 88 | + |
| 89 | + # We're done |
| 90 | + wfDebugLog( 'newtalk', 'Removed `newtalk` flag for user `' . $user->getName() . '`' ); |
| 91 | + wfProfileOut( __METHOD__ ); |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Read "new messages" status from the database |
| 96 | + * |
| 97 | + * @param string $field Table field to check |
| 98 | + * @param string $value Field value to check |
| 99 | + * @return bool |
| 100 | + */ |
| 101 | + private static function getFromDB( $field, $value ) { |
| 102 | + wfProfileIn( __METHOD__ ); |
| 103 | + $dbr = wfGetDB( DB_SLAVE ); |
| 104 | + $row = $dbr->selectRow( 'user_newtalk', '*', array( $field => $value ), __METHOD__ ); |
| 105 | + wfProfileOut( __METHOD__ ); |
| 106 | + return $row !== false; |
| 107 | + } |
| 108 | + |
| 109 | + /** |
| 110 | + * Build the appropriate "new messages" object cache |
| 111 | + * key for a given user |
| 112 | + * |
| 113 | + * @param User $user User to build key for |
| 114 | + * @return string |
| 115 | + */ |
| 116 | + private static function getCacheKey( User $user ) { |
| 117 | + return $user->isLoggedIn() |
| 118 | + ? wfMemcKey( 'newtalk', 'user', $user->getId() ) |
| 119 | + : wfMemcKey( 'newtalk', 'ip', $user->getName() ); |
| 120 | + } |
| 121 | + |
| 122 | + /** |
| 123 | + * Build the appropriate `user_newtalk` column/value pair |
| 124 | + * to check for a given user |
| 125 | + * |
| 126 | + * @param User $user User to build pair for |
| 127 | + * @return array |
| 128 | + */ |
| 129 | + private static function getLookupConds( User $user ) { |
| 130 | + return $user->isLoggedIn() |
| 131 | + ? array( 'user_id', $user->getId() ) |
| 132 | + : array( 'user_ip', $user->getName() ); |
| 133 | + } |
| 134 | + |
| 135 | +} |
| 136 | + |
| 137 | +?> |
Property changes on: branches/robchurch/newtalk/includes/NewTalk.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 138 | + native |