PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/extensions/FlaggedRevs/business/PageStabilityForm.php

https://github.com/ChuguluGames/mediawiki-svn
PHP | 438 lines | 295 code | 41 blank | 102 comment | 65 complexity | decf56a15a4b9f6366fce2ed062bec77 MD5 | raw file
  1. <?php
  2. /**
  3. * Class containing stability settings form business logic
  4. */
  5. abstract class PageStabilityForm extends FRGenericSubmitForm {
  6. /* Form parameters which can be user given */
  7. protected $page = false; # Target page obj
  8. protected $watchThis = null; # Watch checkbox
  9. protected $reviewThis = null; # Auto-review option...
  10. protected $reasonExtra = ''; # Custom/extra reason
  11. protected $reasonSelection = ''; # Reason dropdown key
  12. protected $expiryCustom = ''; # Custom expiry
  13. protected $expirySelection = ''; # Expiry dropdown key
  14. protected $override = -1; # Default version
  15. protected $autoreview = ''; # Autoreview restrictions...
  16. protected $oldConfig = array(); # Old page config
  17. public function getPage() {
  18. return $this->page;
  19. }
  20. public function setPage( Title $value ) {
  21. $this->trySet( $this->page, $value );
  22. }
  23. public function getWatchThis() {
  24. return $this->watchThis;
  25. }
  26. public function setWatchThis( $value ) {
  27. $this->trySet( $this->watchThis, $value );
  28. }
  29. public function getReasonExtra() {
  30. return $this->reasonExtra;
  31. }
  32. public function setReasonExtra( $value ) {
  33. $this->trySet( $this->reasonExtra, $value );
  34. }
  35. public function getReasonSelection() {
  36. return $this->reasonSelection;
  37. }
  38. public function setReasonSelection( $value ) {
  39. $this->trySet( $this->reasonSelection, $value );
  40. }
  41. public function getExpiryCustom() {
  42. return $this->expiryCustom;
  43. }
  44. public function setExpiryCustom( $value ) {
  45. $this->trySet( $this->expiryCustom, $value );
  46. }
  47. public function getExpirySelection() {
  48. return $this->expirySelection;
  49. }
  50. public function setExpirySelection( $value ) {
  51. $this->trySet( $this->expirySelection, $value );
  52. }
  53. public function getAutoreview() {
  54. return $this->autoreview;
  55. }
  56. public function setAutoreview( $value ) {
  57. $this->trySet( $this->autoreview, $value );
  58. }
  59. /*
  60. * Get the final expiry, all inputs considered
  61. * Note: does not check if the expiration is less than wfTimestampNow()
  62. * @return 14-char timestamp or "infinity", or false if the input was invalid
  63. */
  64. public function getExpiry() {
  65. $oldConfig = $this->getOldConfig();
  66. if ( $this->expirySelection == 'existing' ) {
  67. return $oldConfig['expiry'];
  68. } elseif ( $this->expirySelection == 'othertime' ) {
  69. $value = $this->expiryCustom;
  70. } else {
  71. $value = $this->expirySelection;
  72. }
  73. if ( $value == 'infinite' || $value == 'indefinite' || $value == 'infinity' ) {
  74. $time = Block::infinity();
  75. } else {
  76. $unix = strtotime( $value );
  77. # On error returns -1 for PHP <5.1 and false for PHP >=5.1
  78. if ( !$unix || $unix === -1 ) {
  79. return false;
  80. }
  81. // FIXME: non-qualified absolute times are not in users
  82. // specified timezone and there isn't notice about it in the ui
  83. $time = wfTimestamp( TS_MW, $unix );
  84. }
  85. return $time;
  86. }
  87. /*
  88. * Get the final reason, all inputs considered
  89. * @return string
  90. */
  91. public function getReason() {
  92. # Custom reason replaces dropdown
  93. if ( $this->reasonSelection != 'other' ) {
  94. $comment = $this->reasonSelection; // start with dropdown reason
  95. if ( $this->reasonExtra != '' ) {
  96. # Append custom reason
  97. $comment .= wfMsgForContent( 'colon-separator' ) . $this->reasonExtra;
  98. }
  99. } else {
  100. $comment = $this->reasonExtra; // just use custom reason
  101. }
  102. return $comment;
  103. }
  104. /*
  105. * Check that a target is given (e.g. from GET/POST request)
  106. * @return mixed (true on success, error string on failure)
  107. */
  108. protected function doCheckTargetGiven() {
  109. if ( is_null( $this->page ) ) {
  110. return 'stabilize_page_invalid';
  111. }
  112. return true;
  113. }
  114. /*
  115. * Check that the target page is valid
  116. * @param int $flags FOR_SUBMISSION (set on submit)
  117. * @return mixed (true on success, error string on failure)
  118. */
  119. protected function doCheckTarget( $flags = 0 ) {
  120. $flgs = ( $flags & self::FOR_SUBMISSION ) ? Title::GAID_FOR_UPDATE : 0;
  121. if ( !$this->page->getArticleId( $flgs ) ) {
  122. return 'stabilize_page_notexists';
  123. } elseif ( !FlaggedRevs::inReviewNamespace( $this->page ) ) {
  124. return 'stabilize_page_unreviewable';
  125. }
  126. return true;
  127. }
  128. /*
  129. * Verify and clean up parameters (e.g. from POST request)
  130. * @return mixed (true on success, error string on failure)
  131. */
  132. protected function doCheckParameters() {
  133. # Load old config settings from the master
  134. $this->oldConfig = FlaggedPageConfig::getStabilitySettings( $this->page, FR_MASTER );
  135. if ( $this->expiryCustom != '' ) {
  136. // Custom expiry takes precedence
  137. $this->expirySelection = 'othertime';
  138. }
  139. $status = $this->reallyDoCheckParameters(); // check other params...
  140. return $status;
  141. }
  142. /*
  143. * @return mixed (true on success, error string on failure)
  144. */
  145. protected function reallyDoCheckParameters() {
  146. return true;
  147. }
  148. /*
  149. * Can the user change the settings for this page?
  150. * Note: if the current autoreview restriction is too high for this user
  151. * then this will return false. Useful for form selectors.
  152. * @return bool
  153. */
  154. public function isAllowed() {
  155. # Users who cannot edit or review the page cannot set this
  156. return ( $this->page
  157. && $this->page->userCan( 'stablesettings' )
  158. && $this->page->userCan( 'edit' )
  159. && $this->page->userCan( 'review' )
  160. );
  161. }
  162. /*
  163. * Preload existing page settings (e.g. from GET request).
  164. * @return mixed (true on success, error string on failure)
  165. */
  166. public function doPreloadParameters() {
  167. $oldConfig = $this->getOldConfig();
  168. if ( $oldConfig['expiry'] == Block::infinity() ) {
  169. $this->expirySelection = 'infinite'; // no settings set OR indefinite
  170. } else {
  171. $this->expirySelection = 'existing'; // settings set and NOT indefinite
  172. }
  173. return $this->reallyDoPreloadParameters(); // load the params...
  174. }
  175. /*
  176. * @return mixed (true on success, error string on failure)
  177. */
  178. protected function reallyDoPreloadParameters() {
  179. return true;
  180. }
  181. /**
  182. * Submit the form parameters for the page config to the DB.
  183. *
  184. * @return mixed (true on success, error string on failure)
  185. */
  186. public function doSubmit() {
  187. # Double-check permissions
  188. if ( !$this->isAllowed() ) {
  189. return 'stablize_denied';
  190. }
  191. # Parse and cleanup the expiry time given...
  192. $expiry = $this->getExpiry();
  193. if ( $expiry === false ) {
  194. return 'stabilize_expiry_invalid';
  195. } elseif ( $expiry !== Block::infinity() && $expiry < wfTimestampNow() ) {
  196. return 'stabilize_expiry_old';
  197. }
  198. # Update the DB row with the new config...
  199. $changed = FlaggedPageConfig::setStabilitySettings( $this->page, $this->getNewConfig() );
  200. # Log if this actually changed anything...
  201. if ( $changed ) {
  202. $article = new FlaggedPage( $this->page );
  203. if ( FlaggedRevs::useOnlyIfProtected() ) {
  204. # Config may have changed to allow stable versions, so refresh
  205. # the tracking table to account for any hidden reviewed versions...
  206. $frev = FlaggedRevision::determineStable( $this->page, FR_MASTER );
  207. if ( $frev ) {
  208. $article->updateStableVersion( $frev );
  209. } else {
  210. $article->clearStableVersion();
  211. }
  212. }
  213. # Update logs and make a null edit
  214. $nullRev = $this->updateLogsAndHistory( $article );
  215. # Null edit may have been auto-reviewed already
  216. $frev = FlaggedRevision::newFromTitle( $this->page, $nullRev->getId(), FR_MASTER );
  217. $updatesDone = (bool)$frev; // stableVersionUpdates() already called?
  218. # Check if this null edit is to be reviewed...
  219. if ( $this->reviewThis && !$frev ) {
  220. $flags = null;
  221. # Review this revision of the page...
  222. $ok = FlaggedRevs::autoReviewEdit( $article, $this->user, $nullRev, $flags, true );
  223. if ( $ok ) {
  224. FlaggedRevs::markRevisionPatrolled( $nullRev ); // reviewed -> patrolled
  225. $updatesDone = true; // stableVersionUpdates() already called
  226. }
  227. }
  228. # Update page and tracking tables and clear cache.
  229. if ( !$updatesDone ) {
  230. FlaggedRevs::stableVersionUpdates( $this->page );
  231. }
  232. }
  233. # Apply watchlist checkbox value (may be NULL)
  234. $this->updateWatchlist();
  235. # Take this opportunity to purge out expired configurations
  236. FlaggedPageConfig::purgeExpiredConfigurations();
  237. return true;
  238. }
  239. /*
  240. * Do history & log updates:
  241. * (a) Add a new stability log entry
  242. * (b) Add a null edit like the log entry
  243. * @return Revision
  244. */
  245. protected function updateLogsAndHistory( FlaggedPage $article ) {
  246. global $wgContLang;
  247. $newConfig = $this->getNewConfig();
  248. $oldConfig = $this->getOldConfig();
  249. $reason = $this->getReason();
  250. # Insert stability log entry...
  251. FlaggedRevsLog::updateStabilityLog( $this->page, $newConfig, $oldConfig, $reason );
  252. # Build null-edit comment...<action: reason [settings] (expiry)>
  253. if ( FlaggedPageConfig::configIsReset( $newConfig ) ) {
  254. $type = "stable-logentry-reset";
  255. $settings = ''; // no level, expiry info
  256. } else {
  257. $type = "stable-logentry-config";
  258. // Settings message in text form (e.g. [x=a,y=b,z])
  259. $params = FlaggedRevsLog::stabilityLogParams( $newConfig );
  260. $settings = FlaggedRevsLogView::stabilitySettings( $params, true /*content*/ );
  261. }
  262. $comment = $wgContLang->ucfirst(
  263. wfMsgForContent( $type, $this->page->getPrefixedText() ) ); // action
  264. if ( $reason != '' ) {
  265. $comment .= wfMsgForContent( 'colon-separator' ) . $reason; // add reason
  266. }
  267. if ( $settings != '' ) {
  268. $comment .= " {$settings}"; // add settings
  269. }
  270. # Insert a null revision...
  271. $dbw = wfGetDB( DB_MASTER );
  272. $nullRev = Revision::newNullRevision( $dbw, $article->getId(), $comment, true );
  273. $nullRev->insertOn( $dbw );
  274. # Update page record and touch page
  275. $oldLatest = $nullRev->getParentId();
  276. $article->updateRevisionOn( $dbw, $nullRev, $oldLatest );
  277. wfRunHooks( 'NewRevisionFromEditComplete',
  278. array( $article, $nullRev, $oldLatest, $this->user ) );
  279. # Return null Revision object for autoreview check
  280. return $nullRev;
  281. }
  282. /*
  283. * Get current stability config array
  284. * @return array
  285. */
  286. public function getOldConfig() {
  287. if ( $this->getState() == self::FORM_UNREADY ) {
  288. throw new MWException( __CLASS__ . " input fields not set yet.\n");
  289. }
  290. if ( $this->oldConfig === array() && $this->page ) {
  291. $this->oldConfig = FlaggedPageConfig::getStabilitySettings( $this->page );
  292. }
  293. return $this->oldConfig;
  294. }
  295. /*
  296. * Get proposed stability config array
  297. * @return array
  298. */
  299. public function getNewConfig() {
  300. return array(
  301. 'override' => $this->override,
  302. 'autoreview' => $this->autoreview,
  303. 'expiry' => $this->getExpiry(), // TS_MW/infinity
  304. );
  305. }
  306. /*
  307. * (a) Watch page if $watchThis is true
  308. * (b) Unwatch if $watchThis is false
  309. */
  310. protected function updateWatchlist() {
  311. # Apply watchlist checkbox value (may be NULL)
  312. if ( $this->watchThis === true ) {
  313. $this->user->addWatch( $this->page );
  314. } elseif ( $this->watchThis === false ) {
  315. $this->user->removeWatch( $this->page );
  316. }
  317. }
  318. }
  319. // Assumes $wgFlaggedRevsProtection is off
  320. class PageStabilityGeneralForm extends PageStabilityForm {
  321. public function getReviewThis() {
  322. return $this->reviewThis;
  323. }
  324. public function setReviewThis( $value ) {
  325. $this->trySet( $this->reviewThis, $value );
  326. }
  327. public function getOverride() {
  328. return $this->override;
  329. }
  330. public function setOverride( $value ) {
  331. $this->trySet( $this->override, $value );
  332. }
  333. protected function reallyDoPreloadParameters() {
  334. $oldConfig = $this->getOldConfig();
  335. $this->override = $oldConfig['override'];
  336. $this->autoreview = $oldConfig['autoreview'];
  337. $this->watchThis = $this->page->userIsWatching();
  338. return true;
  339. }
  340. protected function reallyDoCheckParameters() {
  341. $this->override = $this->override ? 1 : 0; // default version settings is 0 or 1
  342. // Check autoreview restriction setting
  343. if ( $this->autoreview != '' // restriction other than 'none'
  344. && !in_array( $this->autoreview, FlaggedRevs::getRestrictionLevels() ) )
  345. {
  346. return 'stabilize_invalid_autoreview'; // invalid value
  347. }
  348. if ( !FlaggedRevs::userCanSetAutoreviewLevel( $this->user, $this->autoreview ) ) {
  349. return 'stabilize_denied'; // invalid value
  350. }
  351. return true;
  352. }
  353. }
  354. // Assumes $wgFlaggedRevsProtection is on
  355. class PageStabilityProtectForm extends PageStabilityForm {
  356. protected function reallyDoPreloadParameters() {
  357. $oldConfig = $this->getOldConfig();
  358. $this->autoreview = $oldConfig['autoreview']; // protect level
  359. $this->watchThis = $this->page->userIsWatching();
  360. return true;
  361. }
  362. protected function reallyDoCheckParameters() {
  363. # WMF temp hack...protection limit quota
  364. global $wgFlaggedRevsProtectQuota;
  365. $oldConfig = $this->getOldConfig();
  366. if ( isset( $wgFlaggedRevsProtectQuota ) // quota exists
  367. && $this->autoreview != '' // and we are protecting
  368. && FlaggedPageConfig::getProtectionLevel( $oldConfig ) == 'none' ) // unprotected
  369. {
  370. $dbw = wfGetDB( DB_MASTER );
  371. $count = $dbw->selectField( 'flaggedpage_config', 'COUNT(*)', '', __METHOD__ );
  372. if ( $count >= $wgFlaggedRevsProtectQuota ) {
  373. return 'stabilize_protect_quota';
  374. }
  375. }
  376. # Autoreview only when protecting currently unprotected pages
  377. $this->reviewThis = ( FlaggedPageConfig::getProtectionLevel( $oldConfig ) == 'none' );
  378. # Autoreview restriction => use stable
  379. # No autoreview restriction => site default
  380. $this->override = ( $this->autoreview != '' )
  381. ? 1 // edits require review before being published
  382. : (int)FlaggedRevs::isStableShownByDefault(); // site default
  383. # Check that settings are a valid protection level...
  384. $newConfig = array(
  385. 'override' => $this->override,
  386. 'autoreview' => $this->autoreview
  387. );
  388. if ( FlaggedPageConfig::getProtectionLevel( $newConfig ) == 'invalid' ) {
  389. return 'stabilize_invalid_level'; // double-check configuration
  390. }
  391. # Check autoreview restriction setting
  392. if ( !FlaggedRevs::userCanSetAutoreviewLevel( $this->user, $this->autoreview ) ) {
  393. return 'stabilize_denied'; // invalid value
  394. }
  395. return true;
  396. }
  397. }