r46049 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r46048‎ | r46049 | r46050 >
Date:00:45, 23 January 2009
Author:werdna
Status:ok (Comments)
Tags:
Comment:
Refactor SpecialAbuseFilter code into one file per logical view. Before, there was code for about five different logical pages in the same file.
Modified paths:
  • /branches/change-tagging/extensions/AbuseFilter/AbuseFilter.class.php (modified) (history)
  • /branches/change-tagging/extensions/AbuseFilter/AbuseFilter.php (modified) (history)
  • /branches/change-tagging/extensions/AbuseFilter/SpecialAbuseFilter.php (modified) (history)
  • /branches/change-tagging/extensions/AbuseFilter/Views (added) (history)
  • /branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterView.php (added) (history)
  • /branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterViewEdit.php (added) (history)
  • /branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterViewHistory.php (added) (history)
  • /branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterViewList.php (added) (history)
  • /branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterViewTools.php (added) (history)
  • /branches/change-tagging/extensions/AbuseFilter/Views/edit.js (added) (history)
  • /branches/change-tagging/extensions/AbuseFilter/edit.js (deleted) (history)

Diff [purge]

Index: branches/change-tagging/extensions/AbuseFilter/edit.js
@@ -1,61 +0,0 @@
2 -function doSyntaxCheck()
3 -{
4 - var filter = document.getElementById('wpFilterRules').value;
5 - injectSpinner( document.getElementById( 'mw-abusefilter-syntaxcheck' ), 'abusefilter-syntaxcheck' );
6 - sajax_do_call( 'AbuseFilter::ajaxCheckSyntax', [filter], processSyntaxResult );
7 -}
8 -function processSyntaxResult( request ) {
9 - var response = request.responseText;
10 -
11 - removeSpinner( 'abusefilter-syntaxcheck' );
12 -
13 - var el = document.getElementById( 'mw-abusefilter-syntaxresult' );
14 - el.style.display = 'block';
15 -
16 - if (response.match( /OK/ )) {
17 - // Successful
18 - changeText( el, 'No syntax errors.' );
19 - el.syntaxOk = true;
20 - } else {
21 - var error = response.substr(4);
22 - changeText( el, 'Syntax error: '+error );
23 - el.syntaxOk = false;
24 - }
25 -}
26 -function addText() {
27 - if (document.getElementById('wpFilterBuilder').selectedIndex == 0) {
28 - return;
29 - }
30 -
31 - insertAtCursor(document.getElementById('wpFilterRules'), document.getElementById('wpFilterBuilder').value + " ");
32 - document.getElementById('wpFilterBuilder').selectedIndex = 0;
33 -}
34 -
35 -//From http://clipmarks.com/clipmark/CEFC94CB-94D6-4495-A7AA-791B7355E284/
36 -function insertAtCursor(myField, myValue) {
37 - //IE support
38 - if (document.selection) {
39 - myField.focus();
40 - sel = document.selection.createRange();
41 - sel.text = myValue;
42 - }
43 - //MOZILLA/NETSCAPE support
44 - else if (myField.selectionStart || myField.selectionStart == '0') {
45 - var startPos = myField.selectionStart;
46 - var endPos = myField.selectionEnd;
47 - myField.value = myField.value.substring(0, startPos)
48 - + myValue
49 - + myField.value.substring(endPos, myField.value.length);
50 - } else {
51 - myField.value += myValue;
52 - }
53 -}
54 -
55 -addOnloadHook( function() {
56 - addHandler( document.getElementById( 'wpFilterRules' ), 'keyup', function() {
57 - el = document.getElementById( 'mw-abusefilter-syntaxresult' );
58 - if (el.syntaxOk == true) {
59 - el.style.display = 'none';
60 - }
61 - } );
62 -} );
\ No newline at end of file
Index: branches/change-tagging/extensions/AbuseFilter/AbuseFilter.class.php
@@ -73,7 +73,7 @@
7474 }
7575 }
7676
77 - // Find last 5 authors, for testing.
 77+ // Find last 5 authors.
7878 $dbr = wfGetDB( DB_SLAVE );
7979 $res = $dbr->select( 'revision', 'distinct rev_user_text', array('rev_page' => $title->getArticleId() ), __METHOD__, array( 'order by' => 'rev_timestamp desc', 'limit' => 10 ) );
8080 $users = array();
Index: branches/change-tagging/extensions/AbuseFilter/AbuseFilter.php
@@ -33,6 +33,12 @@
3434 $wgAutoloadClasses['SpecialAbuseLog'] = "$dir/SpecialAbuseLog.php";
3535 $wgAutoloadClasses['SpecialAbuseFilter'] = "$dir/SpecialAbuseFilter.php";
3636
 37+$wgAutoloadClasses['AbuseFilterViewList'] = "$dir/Views/AbuseFilterViewList.php";
 38+$wgAutoloadClasses['AbuseFilterView'] = "$dir/Views/AbuseFilterView.php";
 39+$wgAutoloadClasses['AbuseFilterViewEdit'] = "$dir/Views/AbuseFilterViewEdit.php";
 40+$wgAutoloadClasses['AbuseFilterViewTools'] = "$dir/Views/AbuseFilterViewTools.php";
 41+$wgAutoloadClasses['AbuseFilterViewHistory'] = "$dir/Views/AbuseFilterViewHistory.php";
 42+
3743 $wgSpecialPages['AbuseLog'] = 'SpecialAbuseLog';
3844 $wgSpecialPages['AbuseFilter'] = 'SpecialAbuseFilter';
3945
Index: branches/change-tagging/extensions/AbuseFilter/SpecialAbuseFilter.php
@@ -5,8 +5,6 @@
66 class SpecialAbuseFilter extends SpecialPage {
77
88 var $mSkin;
9 -
10 - static $history_mappings = array( 'af_pattern' => 'afh_pattern', 'af_user' => 'afh_user', 'af_user_text' => 'afh_user_text', 'af_timestamp' => 'afh_timestamp', 'af_comments' => 'afh_comments', 'af_public_comments' => 'afh_public_comments', 'af_deleted' => 'afh_deleted', 'af_id' => 'afh_filter' );
119
1210 function __construct() {
1311 wfLoadExtensionMessages('AbuseFilter');
@@ -17,6 +15,7 @@
1816 global $wgUser,$wgOut,$wgRequest, $wgAbuseFilterStyleVersion, $wgScriptPath;
1917
2018 $wgOut->addExtensionStyle( "{$wgScriptPath}/extensions/AbuseFilter/abusefilter.css?{$wgAbuseFilterStyleVersion}" );
 19+ $view = 'AbuseFilterViewList';
2120
2221 $this->setHeaders();
2322
@@ -28,7 +27,6 @@
2928
3029 // Are we allowed?
3130 if ( !$wgUser->isAllowed( 'abusefilter-view' ) ) {
32 - // Go away.
3331 $this->displayRestrictionError();
3432 return;
3533 }
@@ -39,13 +37,12 @@
4038 }
4139
4240 $this->mSkin = $wgUser->getSkin();
 41+ $this->mHistoryID = null;
4342
4443 $params = array_filter( explode( '/', $subpage ) );
4544
4645 if ($subpage == 'tools') {
47 - // Some useful tools
48 - $this->doTools();
49 - return;
 46+ $view = 'AbuseFilterViewTools';
5047 }
5148
5249 if (!empty($params[0]) && $params[0] == 'history') {
@@ -53,572 +50,24 @@
5451 // ... useless?
5552 } elseif (count($params) == 2) {
5653 ## Second param is a filter ID
57 - $this->showHistory($params[1]);
58 - return;
 54+ $view = 'AbuseFilterViewHistory';
 55+ $this->mFilter = $params[1];
5956 } elseif (count($params) == 4 && $params[2] == 'item') {
60 - $wgOut->addWikiMsg( 'abusefilter-edit-oldwarning', $params[3], $params[1] );
61 - $out = $this->buildFilterEditor( null, $params[1], $params[3] );
62 - $wgOut->addHTML( $out );
63 - $wgOut->addWikiMsg( 'abusefilter-edit-oldwarning', $params[3], $params[1] );
64 - return;
 57+ $this->mFilter = $params[1];
 58+ $this->mHistoryID = $params[3];
 59+ $view = 'AbuseFilterViewEdit';
6560 }
6661 }
6762
68 - if ($output = $this->doEdit()) {
69 - $wgOut->addHTML( $output );
70 - return;
 63+ if ( is_numeric($subpage) || $subpage == 'new' ) {
 64+ $this->mFilter = $subpage;
 65+ $view = 'AbuseFilterViewEdit';
7166 }
72 -
73 - // Show list of filters.
74 - $this->showStatus();
75 -
76 - // Quick links
77 - $wgOut->addWikiMsg( 'abusefilter-links' );
78 - $lists = array( 'tools' );
79 - if ($this->canEdit())
80 - $lists[] = 'new';
81 - $links = '';
82 - $sk = $wgUser->getSkin();
83 - foreach( $lists as $list ) {
84 - $title = $this->getTitle( $list );
85 -
86 - $link = $sk->link( $title, wfMsg( "abusefilter-$list" ) );
87 - $links .= Xml::tags( 'li', null, $link ) . "\n";
88 - }
89 - $links .= Xml::tags( 'li', null, $sk->link( SpecialPage::getTitleFor( 'AbuseLog' ), wfMsg( 'abusefilter-loglink' ) ) );
90 - $links = Xml::tags( 'ul', null, $links );
91 - $wgOut->addHTML( $links );
92 -
93 - // Options.
94 - $conds = array();
95 - $deleted = $wgRequest->getVal( 'deletedfilters' );
96 - $hidedisabled = $wgRequest->getBool( 'hidedisabled' );
97 - if ($deleted == 'show') {
98 - ## Nothing
99 - } elseif ($deleted == 'only') {
100 - $conds['af_deleted'] = 1;
101 - } else { ## hide, or anything else.
102 - $conds['af_deleted'] = 0;
103 - $deleted = 'hide';
104 - }
105 - if ($hidedisabled) {
106 - $conds['af_deleted'] = 0;
107 - $conds['af_enabled'] = 1;
108 - }
109 -
110 - $this->showList( $conds, compact( 'deleted', 'hidedisabled' ) );
111 - }
112 -
113 - function showDeleted() {
114 - $this->showList( array( 'af_deleted' => 1 ) );
115 - }
116 -
117 - function showActive() {
118 - $this->showList( array( 'af_deleted' => 0, 'af_enabled' => 1 ) );
119 - }
120 -
121 - function showHistory( $filter ) {
122 - global $wgRequest,$wgOut;
123 -
124 - global $wgUser;
125 - $sk = $wgUser->getSkin();
126 - $wgOut->setPageTitle( wfMsg( 'abusefilter-history', $filter ) );
127 - $backToFilter_label = wfMsgExt( 'abusefilter-history-backedit', array('parseinline') );
128 - $backToList_label = wfMsgExt( 'abusefilter-history-backlist', array('parseinline') );
129 - $backlinks = $sk->makeKnownLinkObj( $this->getTitle( $filter ), $backToFilter_label ) . ' • ' .
130 - $sk->makeKnownLinkObj( $this->getTitle( ), $backToList_label );
131 - $wgOut->addHTML( Xml::tags( 'p', null, $backlinks ) );
132 -
133 - $pager = new AbuseFilterHistoryPager( $filter, $this );
134 - $table = $pager->getBody();
135 -
136 - $wgOut->addHTML( $pager->getNavigationBar() . $table . $pager->getNavigationBar() );
137 -
138 - return true;
139 - }
140 -
141 - function doTools() {
142 - global $wgRequest,$wgOut;
143 -
144 - // Header
145 - $wgOut->setSubTitle( wfMsg( 'abusefilter-tools-subtitle' ) );
146 - $wgOut->addWikiMsg( 'abusefilter-tools-text' );
14767
148 - // Expression evaluator
149 - $eval = '';
150 - $eval .= Xml::textarea( 'wpTestExpr', "" );
151 - $eval .= Xml::tags( 'p', null, Xml::element( 'input', array( 'type' => 'button', 'id' => 'mw-abusefilter-submitexpr', 'onclick' => 'doExprSubmit();', 'value' => wfMsg( 'abusefilter-tools-submitexpr' ) ) ) );
152 - $eval .= Xml::element( 'p', array( 'id' => 'mw-abusefilter-expr-result' ), ' ' );
153 - $eval = Xml::fieldset( wfMsg( 'abusefilter-tools-expr' ), $eval );
154 - $wgOut->addHTML( $eval );
155 -
156 - // Associated script
157 - $exprScript = "function doExprSubmit()
158 - {
159 - var expr = document.getElementById('wpTestExpr').value;
160 - injectSpinner( document.getElementById( 'mw-abusefilter-submitexpr' ), 'abusefilter-expr' );
161 - sajax_do_call( 'AbuseFilter::ajaxEvaluateExpression', [expr], processExprResult );
162 - }
163 - function processExprResult( request ) {
164 - var response = request.responseText;
165 -
166 - removeSpinner( 'abusefilter-expr' );
167 -
168 - var el = document.getElementById( 'mw-abusefilter-expr-result' );
169 - changeText( el, response );
170 - }
171 - function doReautoSubmit()
172 - {
173 - var name = document.getElementById('reautoconfirm-user').value;
174 - injectSpinner( document.getElementById( 'mw-abusefilter-reautoconfirmsubmit' ), 'abusefilter-reautoconfirm' );
175 - sajax_do_call( 'AbuseFilter::ajaxReAutoconfirm', [name], processReautoconfirm );
176 - }
177 - function processReautoconfirm( request ) {
178 - var response = request.responseText;
179 -
180 - if (strlen(response)) {
181 - jsMsg( response );
182 - }
183 -
184 - removeSpinner( 'abusefilter-reautoconfirm' );
185 - }
186 - ";
187 -
188 - $wgOut->addInlineScript( $exprScript );
189 -
190 - global $wgUser;
191 -
192 - if ($wgUser->isAllowed( 'abusefilter-modify' )) {
193 - // Hacky little box to re-enable autoconfirmed if it got disabled
194 - $rac = '';
195 - $rac .= Xml::inputLabel( wfMsg( 'abusefilter-tools-reautoconfirm-user' ), 'wpReAutoconfirmUser', 'reautoconfirm-user', 45 );
196 - $rac .= Xml::element( 'input', array( 'type' => 'button', 'id' => 'mw-abusefilter-reautoconfirmsubmit', 'onclick' => 'doReautoSubmit();', 'value' => wfMsg( 'abusefilter-tools-reautoconfirm-submit' ) ) );
197 - $rac = Xml::fieldset( wfMsg( 'abusefilter-tools-reautoconfirm' ), $rac );
198 - $wgOut->addHTML( $rac );
199 - }
 68+ $v = new $view( $this, $params );
 69+ $v->show( );
20070 }
20171
202 - function showStatus() {
203 - global $wgMemc,$wgAbuseFilterConditionLimit,$wgOut, $wgLang;
204 -
205 - $overflow_count = (int)$wgMemc->get( AbuseFilter::filterLimitReachedKey() );
206 - $match_count = (int) $wgMemc->get( AbuseFilter::filterMatchesKey() );
207 - $total_count = (int)$wgMemc->get( AbuseFilter::filterUsedKey() );
208 -
209 - if ($total_count>0) {
210 - $overflow_percent = sprintf( "%.2f", 100 * $overflow_count / $total_count );
211 - $match_percent = sprintf( "%.2f", 100 * $match_count / $total_count );
212 -
213 - $status = wfMsgExt( 'abusefilter-status', array( 'parsemag', 'escape' ),
214 - $wgLang->formatNum($total_count),
215 - $wgLang->formatNum($overflow_count),
216 - $wgLang->formatNum($overflow_percent),
217 - $wgLang->formatNum($wgAbuseFilterConditionLimit),
218 - $wgLang->formatNum($match_count),
219 - $wgLang->formatNum($match_percent)
220 - );
221 -
222 - $status = Xml::tags( 'div', array( 'class' => 'mw-abusefilter-status' ), $status );
223 - $wgOut->addHTML( $status );
224 - }
225 - }
226 -
227 - function doEdit( $history_id = null ) {
228 - global $wgRequest, $wgUser;
229 -
230 - $filter = $this->mFilter;
231 -
232 - $editToken = $wgRequest->getVal( 'wpEditToken' );
233 - $didEdit = $this->canEdit() && $wgUser->matchEditToken( $editToken, array( 'abusefilter', $filter ) );
234 -
235 - if ($didEdit) {
236 - // Check syntax
237 - $syntaxerr = AbuseFilter::checkSyntax( $wgRequest->getVal( 'wpFilterRules' ) );
238 - if ($syntaxerr !== true ) {
239 - return $this->buildFilterEditor( wfMsgExt( 'abusefilter-edit-badsyntax', array( 'parseinline' ), array( $syntaxerr ) ), $filter, $history_id );
240 - }
241 -
242 - $dbw = wfGetDB( DB_MASTER );
243 -
244 - list ($newRow, $actions) = $this->loadRequest($filter);
245 -
246 - $newRow = get_object_vars($newRow); // Convert from object to array
247 -
248 - // Set last modifier.
249 - $newRow['af_timestamp'] = $dbw->timestamp( wfTimestampNow() );
250 - $newRow['af_user'] = $wgUser->getId();
251 - $newRow['af_user_text'] = $wgUser->getName();
252 -
253 - $dbw->begin();
254 -
255 - if ($filter == 'new') {
256 - $new_id = $dbw->nextSequenceValue( 'abuse_filter_af_id_seq' );
257 - $is_new = true;
258 - } else {
259 - $new_id = $this->mFilter;
260 - $is_new = false;
261 - }
262 -
263 - $newRow['af_throttled'] = $newRow['af_throttled'] && !$newRow['af_enabled'];
264 -
265 - $newRow['af_id'] = $new_id;
266 -
267 - $dbw->replace( 'abuse_filter', array( 'af_id' ), $newRow, __METHOD__ );
268 -
269 - if ($is_new) {
270 - $new_id = $dbw->insertId();
271 - }
272 -
273 - // Actions
274 - global $wgAbuseFilterAvailableActions;
275 - $deadActions = array();
276 - $actionsRows = array();
277 - foreach( $wgAbuseFilterAvailableActions as $action ) {
278 - // Check if it's set
279 - $enabled = isset($actions[$action]) && (bool)$actions[$action];
280 -
281 - if ($enabled) {
282 - $parameters = $actions[$action]['parameters'];
283 -
284 - $thisRow = array( 'afa_filter' => $new_id, 'afa_consequence' => $action, 'afa_parameters' => implode( "\n", $parameters ) );
285 - $actionsRows[] = $thisRow;
286 - } else {
287 - $deadActions[] = $action;
288 - }
289 - }
290 -
291 - // Create a history row
292 - $afh_row = array();
293 -
294 - foreach( self::$history_mappings as $af_col => $afh_col ) {
295 - $afh_row[$afh_col] = $newRow[$af_col];
296 - }
297 -
298 - // Actions
299 - $displayActions = array();
300 - foreach( $actions as $action ) {
301 - $displayActions[$action['action']] = $action['parameters'];
302 - }
303 - $afh_row['afh_actions'] = serialize($displayActions);
304 -
305 - // Flags
306 - $flags = array();
307 - if ($newRow['af_hidden'])
308 - $flags[] = 'hidden';
309 - if ($newRow['af_enabled'])
310 - $flags[] = 'enabled';
311 - if ($newRow['af_deleted'])
312 - $flags[] = 'deleted';
313 -
314 - $afh_row['afh_flags'] = implode( ",", $flags );
315 -
316 - $afh_row['afh_filter'] = $new_id;
317 -
318 - // Do the update
319 - $dbw->insert( 'abuse_filter_history', $afh_row, __METHOD__ );
320 - $dbw->delete( 'abuse_filter_action', array( 'afa_filter' => $filter, 'afa_consequence' => $deadActions ), __METHOD__ );
321 - $dbw->replace( 'abuse_filter_action', array( array( 'afa_filter', 'afa_consequence' ) ), $actionsRows, __METHOD__ );
322 -
323 - $dbw->commit();
324 -
325 - global $wgOut;
326 -
327 - $wgOut->redirect( $this->getTitle()->getLocalURL( 'result=success&changedfilter='.$new_id ) );
328 - } else {
329 - return $this->buildFilterEditor( null, $filter, $history_id );
330 - }
331 - }
332 -
333 - function buildFilterEditor( $error = '', $filter, $history_id=null ) {
334 - if( $filter === null ) {
335 - return false;
336 - }
337 -
338 - // Build the edit form
339 - global $wgOut,$wgLang,$wgUser;
340 - $sk = $this->mSkin;
341 -
342 - list ($row, $actions) = $this->loadRequest($filter, $history_id);
343 -
344 - if( !$row ) {
345 - return false;
346 - }
347 -
348 - $wgOut->setSubtitle( wfMsg( 'abusefilter-edit-subtitle', $filter, $history_id ) );
349 -
350 - if (isset($row->af_hidden) && $row->af_hidden && !$this->canEdit()) {
351 - return wfMsg( 'abusefilter-edit-denied' );
352 - }
353 -
354 - $output = '';
355 - if ($error) {
356 - $wgOut->addHTML( "<span class=\"error\">$error</span>" );
357 - }
358 -
359 - $wgOut->addHTML( $sk->link( $this->getTitle(), wfMsg( 'abusefilter-history-backlist' ) ) );
360 -
361 - $fields = array();
362 -
363 - $fields['abusefilter-edit-id'] = $this->mFilter == 'new' ? wfMsg( 'abusefilter-edit-new' ) : $filter;
364 - $fields['abusefilter-edit-description'] = Xml::input( 'wpFilterDescription', 45, isset( $row->af_public_comments ) ? $row->af_public_comments : '' );
365 -
366 - // Hit count display
367 - if( !empty($row->af_hit_count) ){
368 - $count = (int)$row->af_hit_count;
369 - $count_display = wfMsgExt( 'abusefilter-hitcount', array( 'parseinline' ),
370 - $wgLang->formatNum( $count )
371 - );
372 - $hitCount = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'AbuseLog' ), $count_display, 'wpSearchFilter='.$row->af_id );
373 -
374 - $fields['abusefilter-edit-hitcount'] = $hitCount;
375 - }
376 -
377 - if ($filter !== 'new') {
378 - // Statistics
379 - global $wgMemc, $wgLang;
380 - $matches_count = $wgMemc->get( AbuseFilter::filterMatchesKey( $filter ) );
381 - $total = $wgMemc->get( AbuseFilter::filterUsedKey() );
382 -
383 - if ($total > 0) {
384 - $matches_percent = sprintf( '%.2f', 100 * $matches_count / $total );
385 - $fields['abusefilter-edit-status-label'] =
386 - wfMsgExt( 'abusefilter-edit-status', array( 'parsemag', 'escape' ),
387 - $wgLang->formatNum($total),
388 - $wgLang->formatNum($matches_count),
389 - $wgLang->formatNum($matches_percent)
390 - );
391 - }
392 - }
393 -
394 - $fields['abusefilter-edit-rules'] = $this->buildEditBox($row);
395 - $fields['abusefilter-edit-notes'] = Xml::textarea( 'wpFilterNotes', ( isset( $row->af_comments ) ? $row->af_comments."\n" : "\n" ) );
396 -
397 - // Build checkboxen
398 - $checkboxes = array( 'hidden', 'enabled', 'deleted' );
399 - $flags = '';
400 -
401 - if (isset($row->af_throttled) && $row->af_throttled) {
402 - global $wgAbuseFilterEmergencyDisableThreshold;
403 - $threshold_percent = sprintf( '%.2f', $wgAbuseFilterEmergencyDisableThreshold * 100 );
404 - $flags .= $wgOut->parse( wfMsg( 'abusefilter-edit-throttled', $wgLang->formatNum( $threshold_percent ) ) );
405 - }
406 -
407 - foreach( $checkboxes as $checkboxId ) {
408 - $message = "abusefilter-edit-$checkboxId";
409 - $dbField = "af_$checkboxId";
410 - $postVar = "wpFilter".ucfirst($checkboxId);
411 -
412 - $checkbox = Xml::checkLabel( wfMsg( $message ), $postVar, $postVar, isset( $row->$dbField ) ? $row->$dbField : false );
413 - $checkbox = Xml::tags( 'p', null, $checkbox );
414 - $flags .= $checkbox;
415 - }
416 - $fields['abusefilter-edit-flags'] = $flags;
417 -
418 - if ($filter != 'new') {
419 - // Last modification details
420 - $user = $sk->userLink( $row->af_user, $row->af_user_text ) . $sk->userToolLinks( $row->af_user, $row->af_user_text );
421 - $fields['abusefilter-edit-lastmod'] = wfMsgExt( 'abusefilter-edit-lastmod-text', array( 'parseinline', 'replaceafter' ), array( $wgLang->timeanddate( $row->af_timestamp ), $user ) );
422 - $history_display = wfMsgExt( 'abusefilter-edit-viewhistory', array( 'parseinline' ) );
423 - $fields['abusefilter-edit-history'] = $sk->makeKnownLinkObj( $this->getTitle( 'history/'.$filter ), $history_display );
424 - }
425 -
426 - $form = Xml::buildForm( $fields );
427 - $form = Xml::fieldset( wfMsg( 'abusefilter-edit-main' ), $form );
428 - $form .= Xml::fieldset( wfMsg( 'abusefilter-edit-consequences' ), $this->buildConsequenceEditor( $row, $actions ) );
429 -
430 - if ($this->canEdit()) {
431 - $form .= Xml::submitButton( wfMsg( 'abusefilter-edit-save' ) );
432 - $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken( array( 'abusefilter', $filter )) );
433 - }
434 -
435 - $form = Xml::tags( 'form', array( 'action' => $this->getTitle( $filter )->getFullURL(), 'method' => 'POST' ), $form );
436 -
437 - $output .= $form;
438 -
439 - return $output;
440 - }
441 -
442 - function buildEditBox( $row ) {
443 - global $wgOut;
444 -
445 - $rules = Xml::textarea( 'wpFilterRules', ( isset( $row->af_pattern ) ? $row->af_pattern."\n" : "\n" ) );
446 -
447 - $dropDown = array(
448 - 'op-arithmetic' => array('+' => 'addition', '-' => 'subtraction', '*' => 'multiplication', '/' => 'divide', '%' => 'modulo', '**' => 'pow'),
449 - 'op-comparison' => array('==' => 'equal', '!=' => 'notequal', '<' => 'lt', '>' => 'gt', '<=' => 'lte', '>=' => 'gte'),
450 - 'op-bool' => array( '!' => 'not', '&' => 'and', '|' => 'or', '^' => 'xor' ),
451 - 'misc' => array( 'val1 ? iftrue : iffalse' => 'ternary', 'in' => 'in', 'like' => 'like', '""' => 'stringlit', ),
452 - 'funcs' => array( 'length(string)' => 'length', 'lcase(string)' => 'lcase', 'ccnorm(string)' => 'ccnorm', 'rmdoubles(string)' => 'rmdoubles', 'specialratio(string)' => 'specialratio', 'norm(string)' => 'norm', 'count(needle,haystack)' => 'count' ),
453 - 'vars' => array( 'ACCOUNTNAME' => 'accountname', 'ACTION' => 'action', 'ADDED_LINES' => 'addedlines', 'EDIT_DELTA' => 'delta', 'EDIT_DIFF' => 'diff', 'NEW_SIZE' => 'newsize', 'OLD_SIZE' => 'oldsize', 'REMOVED_LINES' => 'removedlines', 'SUMMARY' => 'summary', 'ARTICLE_ARTICLEID' => 'article-id', 'ARTICLE_NAMESPACE' => 'article-ns', 'ARTICLE_TEXT' => 'article-text', 'ARTICLE_PREFIXEDTEXT' => 'article-prefixedtext', 'MOVED_FROM_ARTICLEID' => 'movedfrom-id', 'MOVED_FROM_NAMESPACE' => 'movedfrom-ns', 'MOVED_FROM_TEXT' => 'movedfrom-text', 'MOVED_FROM_PREFIXEDTEXT' => 'movedfrom-prefixedtext', 'MOVED_TO_ARTICLEID' => 'movedto-id', 'MOVED_TO_NAMESPACE' => 'movedto-ns', 'MOVED_TO_TEXT' => 'movedto-text', 'MOVED_TO_PREFIXEDTEXT' => 'movedto-prefixedtext', 'USER_EDITCOUNT' => 'user-editcount', 'USER_AGE' => 'user-age', 'USER_NAME' => 'user-name', 'USER_GROUPS' => 'user-groups', 'USER_EMAILCONFIRM' => 'user-emailconfirm'),
454 - );
455 -
456 - // Generate builder drop-down
457 - $builder = '';
458 -
459 - $builder .= Xml::option( wfMsg( "abusefilter-edit-builder-select") );
460 -
461 - foreach( $dropDown as $group => $values ) {
462 - $builder .= Xml::openElement( 'optgroup', array( 'label' => wfMsg( "abusefilter-edit-builder-group-$group" ) ) ) . "\n";
463 -
464 - foreach( $values as $content => $name ) {
465 - $builder .= Xml::option( wfMsg( "abusefilter-edit-builder-$group-$name" ), $content ) . "\n";
466 - }
467 -
468 - $builder .= Xml::closeElement( 'optgroup' ) . "\n";
469 - }
470 -
471 - $rules .= Xml::tags( 'select', array( 'id' => 'wpFilterBuilder', 'onchange' => 'addText();' ), $builder );
472 -
473 - // Add syntax checking
474 - $rules .= Xml::element( 'input', array( 'type' => 'button', 'onclick' => 'doSyntaxCheck()', 'value' => wfMsg( 'abusefilter-edit-check' ), 'id' => 'mw-abusefilter-syntaxcheck' ) );
475 - $rules .= Xml::element( 'div', array( 'id' => 'mw-abusefilter-syntaxresult', 'style' => 'display: none;' ), '&nbsp;' );
476 -
477 - // Add script
478 - $wgOut->addInlineScript( file_get_contents(dirname(__FILE__)."/edit.js") );
479 -
480 - return $rules;
481 - }
482 -
483 - function buildConsequenceEditor( $row, $actions ) {
484 - global $wgAbuseFilterAvailableActions;
485 - $setActions = array();
486 - foreach( $wgAbuseFilterAvailableActions as $action ) {
487 - $setActions[$action] = array_key_exists( $action, $actions );
488 - }
489 -
490 - $output = '';
491 -
492 - // Special case: flagging - always on.
493 - $checkbox = Xml::checkLabel( wfMsg( 'abusefilter-edit-action-flag' ), 'wpFilterActionFlag', 'wpFilterActionFlag', true, array( 'disabled' => '1' ) );
494 - $output .= Xml::tags( 'p', null, $checkbox );
495 -
496 - // Special case: throttling
497 - $throttleSettings = Xml::checkLabel( wfMsg( 'abusefilter-edit-action-throttle' ), 'wpFilterActionThrottle', 'wpFilterActionThrottle', $setActions['throttle'] );
498 - $throttleFields = array();
499 -
500 - if ($setActions['throttle']) {
501 - array_shift( $actions['throttle']['parameters'] );
502 - $throttleRate = explode(',',$actions['throttle']['parameters'][0]);
503 - $throttleCount = $throttleRate[0];
504 - $throttlePeriod = $throttleRate[1];
505 -
506 - $throttleGroups = implode("\n", array_slice($actions['throttle']['parameters'], 1 ) );
507 - } else {
508 - $throttleCount = 3;
509 - $throttlePeriod = 60;
510 -
511 - $throttleGroups = "user\n";
512 - }
513 -
514 - $throttleFields['abusefilter-edit-throttle-count'] = Xml::input( 'wpFilterThrottleCount', 20, $throttleCount );
515 - $throttleFields['abusefilter-edit-throttle-period'] = wfMsgExt( 'abusefilter-edit-throttle-seconds', array( 'parseinline', 'replaceafter' ), array(Xml::input( 'wpFilterThrottlePeriod', 20, $throttlePeriod ) ) );
516 - $throttleFields['abusefilter-edit-throttle-groups'] = Xml::textarea( 'wpFilterThrottleGroups', $throttleGroups."\n" );
517 - $throttleSettings .= Xml::buildForm( $throttleFields );
518 - $output .= Xml::tags( 'p', null, $throttleSettings );
519 -
520 - // Special case: Warning
521 - $checkbox = Xml::checkLabel( wfMsg( 'abusefilter-edit-action-warn' ), 'wpFilterActionWarn', 'wpFilterActionWarn', $setActions['warn'] );
522 - $output .= Xml::tags( 'p', null, $checkbox );
523 -
524 - $warnMsg = empty($setActions['warn']) ? 'abusefilter-warning' : $actions['warn']['parameters'][0];
525 - $warnFields['abusefilter-edit-warn-message'] = Xml::input( 'wpFilterWarnMessage', 45, $warnMsg );
526 - $output .= Xml::tags( 'p', null, Xml::buildForm( $warnFields ) );
527 -
528 - // Special case: tagging
529 - if ($setActions['tag']) {
530 - $tags = $actions['tag']['parameters'];
531 - } else {
532 - $tags = array();
533 - }
534 -
535 - $checkbox = Xml::checkLabel( wfMsg('abusefilter-edit-action-tag'), 'wpFilterActionTag', 'wpFilterActionTag', $setActions['tag'] );
536 - $output .= Xml::tags( 'p', null, $checkbox );
537 -
538 - $tagFields['abusefilter-edit-tag-tag'] = Xml::textarea( 'wpFilterTags', implode( "\n", $tags ) );
539 - $output .= Xml::tags( 'p', null, Xml::buildForm( $tagFields ) );
540 -
541 - // The remainder are just toggles
542 - $remainingActions = array_diff( $wgAbuseFilterAvailableActions, array( 'flag', 'throttle', 'warn', 'tag' ) );
543 -
544 - foreach( $remainingActions as $action ) {
545 - $message = 'abusefilter-edit-action-'.$action;
546 - $form_field = 'wpFilterAction' . ucfirst($action);
547 - $status = $setActions[$action];
548 -
549 - $thisAction = Xml::checkLabel( wfMsg( $message ), $form_field, $form_field, $status );
550 - $thisAction = Xml::tags( 'p', null, $thisAction );
551 -
552 - $output .= $thisAction;
553 - }
554 -
555 - return $output;
556 - }
557 -
558 - function loadFilterData( $id ) {
559 -
560 - if ($id == 'new') {
561 - return array( new StdClass, array() );
562 - }
563 -
564 - $dbr = wfGetDB( DB_SLAVE );
565 -
566 - // Load the main row
567 - $row = $dbr->selectRow( 'abuse_filter', '*', array( 'af_id' => $id ), __METHOD__ );
568 -
569 - if (!isset($row) || !isset($row->af_id) || !$row->af_id)
570 - return null;
571 -
572 - // Load the actions
573 - $actions = array();
574 - $res = $dbr->select( 'abuse_filter_action', '*', array( 'afa_filter' => $id), __METHOD__ );
575 - while ( $actionRow = $dbr->fetchObject( $res ) ) {
576 - $thisAction = array();
577 - $thisAction['action'] = $actionRow->afa_consequence;
578 - $thisAction['parameters'] = explode( "\n", $actionRow->afa_parameters );
579 -
580 - $actions[$actionRow->afa_consequence] = $thisAction;
581 - }
582 -
583 - return array( $row, $actions );
584 - }
585 -
586 - function loadHistoryItem( $id ) {
587 - $dbr = wfGetDB( DB_SLAVE );
588 -
589 - // Load the row.
590 - $row = $dbr->selectRow( 'abuse_filter_history', '*', array( 'afh_id' => $id ), __METHOD__ );
591 -
592 - ## Translate into an abuse_filter row with some black magic. This is ever so slightly evil!
593 - $af_row = new StdClass;
594 -
595 - foreach (self::$history_mappings as $af_col => $afh_col ) {
596 - $af_row->$af_col = $row->$afh_col;
597 - }
598 -
599 - ## Process flags
600 -
601 - $af_row->af_deleted = 0;
602 - $af_row->af_hidden = 0;
603 - $af_row->af_enabled = 0;
604 -
605 - $flags = explode(',', $row->afh_flags );
606 - foreach( $flags as $flag ) {
607 - $col_name = "af_$flag";
608 - $af_row->$col_name = 1;
609 - }
610 -
611 - ## Process actions
612 - $actions_raw = unserialize($row->afh_actions);
613 - $actions_output = array();
614 -
615 - foreach( $actions_raw as $action => $parameters ) {
616 - $actions_output[$action] = array( 'action' => $action, 'parameters' => $parameters );
617 - }
618 -
619 -
620 - return array( $af_row, $actions_output );
621 - }
622 -
62372 function loadParameters( $subpage ) {
62473 global $wgRequest;
62574
@@ -629,302 +78,4 @@
63079 }
63180 $this->mFilter = $filter;
63281 }
633 -
634 - function loadRequest( $filter, $history_id = null ) {
635 - static $row = null;
636 - static $actions = null;
637 - global $wgRequest;
638 -
639 - if (!is_null($actions) && !is_null($row)) {
640 - return array($row,$actions);
641 - } elseif ($wgRequest->wasPosted()) {
642 - ## Nothing, we do it all later
643 - } elseif ( $history_id ) {
644 - return $this->loadHistoryItem( $history_id );
645 - } else {
646 - return $this->loadFilterData( $filter );
647 - }
648 -
649 - // We need some details like last editor
650 - list($row) = $this->loadFilterData( $filter );
651 -
652 - $textLoads = array( 'af_public_comments' => 'wpFilterDescription', 'af_pattern' => 'wpFilterRules', 'af_comments' => 'wpFilterNotes' );
653 -
654 - foreach( $textLoads as $col => $field ) {
655 - $row->$col = trim($wgRequest->getVal( $field ));
656 - }
657 -
658 - $row->af_deleted = $wgRequest->getBool( 'wpFilterDeleted' );
659 - $row->af_enabled = $wgRequest->getBool( 'wpFilterEnabled' ) && !$row->af_deleted;
660 - $row->af_hidden = $wgRequest->getBool( 'wpFilterHidden' );
661 -
662 - // Actions
663 - global $wgAbuseFilterAvailableActions;
664 - $actions = array();
665 - foreach( $wgAbuseFilterAvailableActions as $action ) {
666 - // Check if it's set
667 - $enabled = $wgRequest->getBool( 'wpFilterAction'.ucfirst($action) );
668 -
669 - if ($enabled) {
670 - $parameters = array();
671 -
672 - if ($action == 'throttle') {
673 - // Grumble grumble.
674 - // We need to load the parameters
675 - $throttleCount = $wgRequest->getIntOrNull( 'wpFilterThrottleCount' );
676 - $throttlePeriod = $wgRequest->getIntOrNull( 'wpFilterThrottlePeriod' );
677 - $throttleGroups = explode("\n", trim( $wgRequest->getText( 'wpFilterThrottleGroups' ) ) );
678 -
679 - $parameters[0] = $this->mFilter; // For now, anyway
680 - $parameters[1] = "$throttleCount,$throttlePeriod";
681 - $parameters = array_merge( $parameters, $throttleGroups );
682 - } elseif ($action == 'warn') {
683 - $parameters[0] = $wgRequest->getVal( 'wpFilterWarnMessage' );
684 - } elseif ($action == 'tag') {
685 - $parameters = explode("\n", $wgRequest->getText( 'wpFilterTags' ) );
686 - }
687 -
688 - $thisAction = array( 'action' => $action, 'parameters' => $parameters );
689 - $actions[$action] = $thisAction;
690 - }
691 - }
692 -
693 - return array( $row, $actions );
694 - }
695 -
696 - function canEdit() {
697 - global $wgUser;
698 - static $canEdit = 'unset';
699 -
700 - if ($canEdit == 'unset') {
701 - $canEdit = $wgUser->isAllowed( 'abusefilter-modify' );
702 - }
703 -
704 - return $canEdit;
705 - }
706 -
707 - function showList( $conds = array( 'af_deleted' => 0 ), $optarray = array() ) {
708 - global $wgOut,$wgUser;
709 -
710 - $sk = $this->mSkin = $wgUser->getSkin();
711 -
712 - $output = '';
713 - $output .= Xml::element( 'h2', null, wfMsgExt( 'abusefilter-list', array( 'parseinline' ) ) );
714 -
715 - $pager = new AbuseFilterPager( $this, $conds );
716 -
717 - extract($optarray);
718 -
719 - ## Options form
720 - $options = '';
721 - $fields = array();
722 - $fields['abusefilter-list-options-deleted'] = Xml::radioLabel( wfMsg( 'abusefilter-list-options-deleted-show' ), 'deletedfilters', 'show', 'mw-abusefilter-deletedfilters-show', $deleted == 'show' );
723 - $fields['abusefilter-list-options-deleted'] .= Xml::radioLabel( wfMsg( 'abusefilter-list-options-deleted-hide' ), 'deletedfilters', 'hide', 'mw-abusefilter-deletedfilters-hide', $deleted == 'hide' );
724 - $fields['abusefilter-list-options-deleted'] .= Xml::radioLabel( wfMsg( 'abusefilter-list-options-deleted-only' ), 'deletedfilters', 'only', 'mw-abusefilter-deletedfilters-only', $deleted == 'only' );
725 - $fields['abusefilter-list-options-disabled'] = Xml::checkLabel( wfMsg( 'abusefilter-list-options-hidedisabled' ), 'hidedisabled', 'mw-abusefilter-disabledfilters-hide', $hidedisabled );
726 - $fields['abusefilter-list-limit'] = $pager->getLimitSelect();
727 -
728 - $options = Xml::buildForm( $fields, 'abusefilter-list-options-submit' );
729 - $options .= Xml::hidden( 'title', $this->getTitle()->getPrefixedText() );
730 - $options = Xml::tags( 'form', array( 'method' => 'get', 'action' => $this->getTitle()->getFullURL() ), $options );
731 - $options = Xml::fieldset( wfMsg( 'abusefilter-list-options' ), $options );
732 -
733 - $output .= $options;
734 -
735 - $output .=
736 - $pager->getNavigationBar() .
737 - $pager->getBody() .
738 - $pager->getNavigationBar();
739 -
740 - $wgOut->addHTML( $output );
741 - }
742 -}
743 -
744 -class AbuseFilterPager extends TablePager {
745 -
746 - function __construct( $page, $conds ) {
747 - $this->mPage = $page;
748 - $this->mConds = $conds;
749 - parent::__construct();
750 - }
751 -
752 - function getQueryInfo() {
753 - $dbr = wfGetDB( DB_SLAVE );
754 - #$this->mConds[] = 'afa_filter=af_id';
755 - $abuse_filter = $dbr->tableName( 'abuse_filter' );
756 - return array( 'tables' => array('abuse_filter', 'abuse_filter_action'),
757 - 'fields' => array( 'af_id', '(af_enabled | af_deleted << 1) AS status', 'af_public_comments', 'af_hidden', 'af_hit_count', 'af_timestamp', 'af_user_text', 'af_user', 'group_concat(afa_consequence) AS consequences' ),
758 - 'conds' => $this->mConds,
759 - 'options' => array( 'GROUP BY' => 'af_id' ),
760 - 'join_conds' => array( 'abuse_filter_action' => array( 'LEFT JOIN', 'afa_filter=af_id' ) ) );
761 - }
762 -
763 - function getIndexField() {
764 - return 'af_id';
765 - }
766 -
767 - function getFieldNames() {
768 - static $headers = null;
769 -
770 - if (!empty($headers)) {
771 - return $headers;
772 - }
773 -
774 - $headers = array( 'af_id' => 'abusefilter-list-id', 'af_public_comments' => 'abusefilter-list-public', 'consequences' => 'abusefilter-list-consequences', 'status' => 'abusefilter-list-status', 'af_timestamp' => 'abusefilter-list-lastmodified', 'af_hidden' => 'abusefilter-list-visibility', 'af_hit_count' => 'abusefilter-list-hitcount' );
775 -
776 - $headers = array_map( 'wfMsg', $headers );
777 -
778 - return $headers;
779 - }
780 -
781 - function formatValue( $name, $value ) {
782 - global $wgOut,$wgLang;
783 -
784 - static $sk=null;
785 -
786 - if (empty($sk)) {
787 - global $wgUser;
788 - $sk = $wgUser->getSkin();
789 - }
790 -
791 - $row = $this->mCurrentRow;
792 -
793 - switch($name) {
794 - case 'af_id':
795 - return $sk->link( SpecialPage::getTitleFor( 'AbuseFilter', intval($value) ), intval($value) );
796 - case 'af_public_comments':
797 - return $wgOut->parse( $value );
798 - case 'consequences':
799 - return htmlspecialchars($value);
800 - case 'status':
801 - if ($value & 2)
802 - return wfMsgExt( 'abusefilter-deleted', 'parseinline' );
803 - elseif ($value & 1)
804 - return wfMsgExt( 'abusefilter-enabled', 'parseinline' );
805 - else
806 - return wfMsgExt( 'abusefilter-disabled', 'parseinline' );
807 - case 'af_hidden':
808 - $msg = $value ? 'abusefilter-hidden' : 'abusefilter-unhidden';
809 - return wfMsgExt( $msg, 'parseinline' );
810 - case 'af_hit_count':
811 - $count_display = wfMsgExt( 'abusefilter-hitcount', array( 'parseinline' ), $wgLang->formatNum( $value ) );
812 - $link = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'AbuseLog' ), $count_display, 'wpSearchFilter='.$row->af_id );
813 - return $link;
814 - case 'af_timestamp':
815 - $userLink = $sk->userLink( $row->af_user, $row->af_user_text ) . $sk->userToolLinks( $row->af_user, $row->af_user_text );
816 - return wfMsgExt( 'abusefilter-edit-lastmod-text', array( 'replaceafter', 'parseinline' ), array( $wgLang->timeanddate($value), $userLink ) );
817 - default:
818 - throw new MWException( "Unknown row type $name!" );
819 - }
820 - }
821 -
822 - function getDefaultSort() {
823 - return 'af_id';
824 - }
825 -
826 - function isFieldSortable($name) {
827 - $sortable_fields = array( 'af_id', 'status', 'af_hit_count', 'af_throttled', 'af_user_text', 'af_timestamp' );
828 - return in_array( $name, $sortable_fields );
829 - }
830 -}
831 -
832 -class AbuseFilterHistoryPager extends TablePager {
833 -
834 - function __construct( $filter, $page ) {
835 - $this->mFilter = $filter;
836 - $this->mPage = $page;
837 - $this->mDefaultDirection = true;
838 - parent::__construct();
839 - }
840 -
841 - function getFieldNames() {
842 - static $headers = null;
843 -
844 - if (!empty($headers)) {
845 - return $headers;
846 - }
847 -
848 - $headers = array( 'afh_timestamp' => 'abusefilter-history-timestamp', 'afh_user_text' => 'abusefilter-history-user', 'afh_public_comments' => 'abusefilter-history-public',
849 - 'afh_flags' => 'abusefilter-history-flags', 'afh_pattern' => 'abusefilter-history-filter', 'afh_comments' => 'abusefilter-history-comments', 'afh_actions' => 'abusefilter-history-actions' );
850 -
851 - $headers = array_map( 'wfMsg', $headers );
852 -
853 - return $headers;
854 - }
855 -
856 - function formatValue( $name, $value ) {
857 - global $wgOut,$wgLang;
858 -
859 - static $sk=null;
860 -
861 - if (empty($sk)) {
862 - global $wgUser;
863 - $sk = $wgUser->getSkin();
864 - }
865 -
866 - $row = $this->mCurrentRow;
867 -
868 - switch($name) {
869 - case 'afh_timestamp':
870 - $title = SpecialPage::getTitleFor( 'AbuseFilter', 'history/'.$this->mFilter.'/item/'.$row->afh_id );
871 - return $sk->link( $title, $wgLang->timeanddate( $row->afh_timestamp ) );
872 - case 'afh_user_text':
873 - return $sk->userLink( $row->afh_user, $row->afh_user_text ) . ' ' . $sk->userToolLinks( $row->afh_user, $row->afh_user_text );
874 - case 'afh_public_comments':
875 - return $wgOut->parse( $value );
876 - case 'afh_flags':
877 - $flags = array_filter( explode( ',', $value ) );
878 - $flags_display = array();
879 - foreach( $flags as $flag ) {
880 - $flags_display[] = wfMsg( "abusefilter-history-$flag" );
881 - }
882 - return implode( ', ', $flags_display );
883 - case 'afh_pattern':
884 - return htmlspecialchars( $wgLang->truncate( $value, 200, '...' ) );
885 - case 'afh_comments':
886 - return htmlspecialchars( $wgLang->truncate( $value, 200, '...' ) );
887 - case 'afh_actions':
888 - $actions = unserialize( $value );
889 -
890 - $display_actions = '';
891 -
892 - foreach( $actions as $action => $parameters ) {
893 - $display_actions .= Xml::tags( 'li', null, wfMsgExt( 'abusefilter-history-action', array( 'parseinline' ), array($action, implode('; ', $parameters)) ) );
894 - }
895 - $display_actions = Xml::tags( 'ul', null, $display_actions );
896 -
897 - return $display_actions;
898 - }
899 -
900 - return "Unable to format name $name\n";
901 - }
902 -
903 - function getQueryInfo() {
904 - return array(
905 - 'tables' => 'abuse_filter_history',
906 - 'fields' => array( 'afh_timestamp', 'afh_user_text', 'afh_public_comments', 'afh_flags', 'afh_pattern', 'afh_comments', 'afh_actions', 'afh_id', 'afh_user' ),
907 - 'conds' => array( 'afh_filter' => $this->mFilter ),
908 - );
909 - }
910 -
911 - function getIndexField() {
912 - return 'afh_timestamp';
913 - }
914 -
915 - function getDefaultSort() {
916 - return 'afh_timestamp';
917 - }
918 -
919 - function isFieldSortable($name) {
920 - $sortable_fields = array( 'afh_timestamp', 'afh_user_text' );
921 - return in_array( $name, $sortable_fields );
922 - }
923 -
924 - /**
925 - * Title used for self-links. Override this if you want to be able to
926 - * use a title other than $wgTitle
927 - */
928 - function getTitle() {
929 - return $this->mPage->getTitle( "history/".$this->mFilter );
930 - }
93182 }
\ No newline at end of file
Index: branches/change-tagging/extensions/AbuseFilter/Views/edit.js
@@ -0,0 +1,61 @@
 2+function doSyntaxCheck()
 3+{
 4+ var filter = document.getElementById('wpFilterRules').value;
 5+ injectSpinner( document.getElementById( 'mw-abusefilter-syntaxcheck' ), 'abusefilter-syntaxcheck' );
 6+ sajax_do_call( 'AbuseFilter::ajaxCheckSyntax', [filter], processSyntaxResult );
 7+}
 8+function processSyntaxResult( request ) {
 9+ var response = request.responseText;
 10+
 11+ removeSpinner( 'abusefilter-syntaxcheck' );
 12+
 13+ var el = document.getElementById( 'mw-abusefilter-syntaxresult' );
 14+ el.style.display = 'block';
 15+
 16+ if (response.match( /OK/ )) {
 17+ // Successful
 18+ changeText( el, 'No syntax errors.' );
 19+ el.syntaxOk = true;
 20+ } else {
 21+ var error = response.substr(4);
 22+ changeText( el, 'Syntax error: '+error );
 23+ el.syntaxOk = false;
 24+ }
 25+}
 26+function addText() {
 27+ if (document.getElementById('wpFilterBuilder').selectedIndex == 0) {
 28+ return;
 29+ }
 30+
 31+ insertAtCursor(document.getElementById('wpFilterRules'), document.getElementById('wpFilterBuilder').value + " ");
 32+ document.getElementById('wpFilterBuilder').selectedIndex = 0;
 33+}
 34+
 35+//From http://clipmarks.com/clipmark/CEFC94CB-94D6-4495-A7AA-791B7355E284/
 36+function insertAtCursor(myField, myValue) {
 37+ //IE support
 38+ if (document.selection) {
 39+ myField.focus();
 40+ sel = document.selection.createRange();
 41+ sel.text = myValue;
 42+ }
 43+ //MOZILLA/NETSCAPE support
 44+ else if (myField.selectionStart || myField.selectionStart == '0') {
 45+ var startPos = myField.selectionStart;
 46+ var endPos = myField.selectionEnd;
 47+ myField.value = myField.value.substring(0, startPos)
 48+ + myValue
 49+ + myField.value.substring(endPos, myField.value.length);
 50+ } else {
 51+ myField.value += myValue;
 52+ }
 53+}
 54+
 55+addOnloadHook( function() {
 56+ addHandler( document.getElementById( 'wpFilterRules' ), 'keyup', function() {
 57+ el = document.getElementById( 'mw-abusefilter-syntaxresult' );
 58+ if (el.syntaxOk == true) {
 59+ el.style.display = 'none';
 60+ }
 61+ } );
 62+} );
\ No newline at end of file
Property changes on: branches/change-tagging/extensions/AbuseFilter/Views/edit.js
___________________________________________________________________
Name: svn:eol-style
163 + native
Index: branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterViewList.php
@@ -0,0 +1,202 @@
 2+<?php
 3+
 4+if (!defined( 'MEDIAWIKI' ))
 5+ die();
 6+
 7+class AbuseFilterViewList extends AbuseFilterView {
 8+ function show( ) {
 9+ global $wgUser, $wgOut, $wgRequest;
 10+
 11+ $sk = $wgUser->getSkin();
 12+
 13+ // Show list of filters.
 14+ $this->showStatus();
 15+
 16+ // Quick links
 17+ $wgOut->addWikiMsg( 'abusefilter-links' );
 18+ $lists = array( 'tools' );
 19+ if ($this->canEdit())
 20+ $lists[] = 'new';
 21+ $links = '';
 22+ $sk = $wgUser->getSkin();
 23+ foreach( $lists as $list ) {
 24+ $title = $this->getTitle( $list );
 25+
 26+ $link = $sk->link( $title, wfMsg( "abusefilter-$list" ) );
 27+ $links .= Xml::tags( 'li', null, $link ) . "\n";
 28+ }
 29+ $links .= Xml::tags( 'li', null, $sk->link( SpecialPage::getTitleFor( 'AbuseLog' ), wfMsg( 'abusefilter-loglink' ) ) );
 30+ $links = Xml::tags( 'ul', null, $links );
 31+ $wgOut->addHTML( $links );
 32+
 33+ // Options.
 34+ $conds = array();
 35+ $deleted = $wgRequest->getVal( 'deletedfilters' );
 36+ $hidedisabled = $wgRequest->getBool( 'hidedisabled' );
 37+ if ($deleted == 'show') {
 38+ ## Nothing
 39+ } elseif ($deleted == 'only') {
 40+ $conds['af_deleted'] = 1;
 41+ } else { ## hide, or anything else.
 42+ $conds['af_deleted'] = 0;
 43+ $deleted = 'hide';
 44+ }
 45+ if ($hidedisabled) {
 46+ $conds['af_deleted'] = 0;
 47+ $conds['af_enabled'] = 1;
 48+ }
 49+
 50+ $this->showList( $conds, compact( 'deleted', 'hidedisabled' ) );
 51+ }
 52+
 53+ function showList( $conds = array( 'af_deleted' => 0 ), $optarray = array() ) {
 54+ global $wgOut,$wgUser;
 55+
 56+ $sk = $this->mSkin = $wgUser->getSkin();
 57+
 58+ $output = '';
 59+ $output .= Xml::element( 'h2', null, wfMsgExt( 'abusefilter-list', array( 'parseinline' ) ) );
 60+
 61+ $pager = new AbuseFilterPager( $this, $conds );
 62+
 63+ extract($optarray);
 64+
 65+ ## Options form
 66+ $options = '';
 67+ $fields = array();
 68+ $fields['abusefilter-list-options-deleted'] = Xml::radioLabel( wfMsg( 'abusefilter-list-options-deleted-show' ), 'deletedfilters', 'show', 'mw-abusefilter-deletedfilters-show', $deleted == 'show' );
 69+ $fields['abusefilter-list-options-deleted'] .= Xml::radioLabel( wfMsg( 'abusefilter-list-options-deleted-hide' ), 'deletedfilters', 'hide', 'mw-abusefilter-deletedfilters-hide', $deleted == 'hide' );
 70+ $fields['abusefilter-list-options-deleted'] .= Xml::radioLabel( wfMsg( 'abusefilter-list-options-deleted-only' ), 'deletedfilters', 'only', 'mw-abusefilter-deletedfilters-only', $deleted == 'only' );
 71+ $fields['abusefilter-list-options-disabled'] = Xml::checkLabel( wfMsg( 'abusefilter-list-options-hidedisabled' ), 'hidedisabled', 'mw-abusefilter-disabledfilters-hide', $hidedisabled );
 72+ $fields['abusefilter-list-limit'] = $pager->getLimitSelect();
 73+
 74+ $options = Xml::buildForm( $fields, 'abusefilter-list-options-submit' );
 75+ $options .= Xml::hidden( 'title', $this->getTitle()->getPrefixedText() );
 76+ $options = Xml::tags( 'form', array( 'method' => 'get', 'action' => $this->getTitle()->getFullURL() ), $options );
 77+ $options = Xml::fieldset( wfMsg( 'abusefilter-list-options' ), $options );
 78+
 79+ $output .= $options;
 80+
 81+ $output .=
 82+ $pager->getNavigationBar() .
 83+ $pager->getBody() .
 84+ $pager->getNavigationBar();
 85+
 86+ $wgOut->addHTML( $output );
 87+ }
 88+
 89+ function showStatus() {
 90+ global $wgMemc,$wgAbuseFilterConditionLimit,$wgOut, $wgLang;
 91+
 92+ $overflow_count = (int)$wgMemc->get( AbuseFilter::filterLimitReachedKey() );
 93+ $match_count = (int) $wgMemc->get( AbuseFilter::filterMatchesKey() );
 94+ $total_count = (int)$wgMemc->get( AbuseFilter::filterUsedKey() );
 95+
 96+ if ($total_count>0) {
 97+ $overflow_percent = sprintf( "%.2f", 100 * $overflow_count / $total_count );
 98+ $match_percent = sprintf( "%.2f", 100 * $match_count / $total_count );
 99+
 100+ $status = wfMsgExt( 'abusefilter-status', array( 'parsemag', 'escape' ),
 101+ $wgLang->formatNum($total_count),
 102+ $wgLang->formatNum($overflow_count),
 103+ $wgLang->formatNum($overflow_percent),
 104+ $wgLang->formatNum($wgAbuseFilterConditionLimit),
 105+ $wgLang->formatNum($match_count),
 106+ $wgLang->formatNum($match_percent)
 107+ );
 108+
 109+ $status = Xml::tags( 'div', array( 'class' => 'mw-abusefilter-status' ), $status );
 110+ $wgOut->addHTML( $status );
 111+ }
 112+ }
 113+}
 114+
 115+
 116+// Probably no need to autoload this class, as it will only be called from the class above.
 117+class AbuseFilterPager extends TablePager {
 118+
 119+ function __construct( $page, $conds ) {
 120+ $this->mPage = $page;
 121+ $this->mConds = $conds;
 122+ parent::__construct();
 123+ }
 124+
 125+ function getQueryInfo() {
 126+ $dbr = wfGetDB( DB_SLAVE );
 127+ #$this->mConds[] = 'afa_filter=af_id';
 128+ $abuse_filter = $dbr->tableName( 'abuse_filter' );
 129+ return array( 'tables' => array('abuse_filter', 'abuse_filter_action'),
 130+ 'fields' => array( 'af_id', '(af_enabled | af_deleted << 1) AS status', 'af_public_comments', 'af_hidden', 'af_hit_count', 'af_timestamp', 'af_user_text', 'af_user', 'group_concat(afa_consequence) AS consequences' ),
 131+ 'conds' => $this->mConds,
 132+ 'options' => array( 'GROUP BY' => 'af_id' ),
 133+ 'join_conds' => array( 'abuse_filter_action' => array( 'LEFT JOIN', 'afa_filter=af_id' ) ) );
 134+ }
 135+
 136+ function getIndexField() {
 137+ return 'af_id';
 138+ }
 139+
 140+ function getFieldNames() {
 141+ static $headers = null;
 142+
 143+ if (!empty($headers)) {
 144+ return $headers;
 145+ }
 146+
 147+ $headers = array( 'af_id' => 'abusefilter-list-id', 'af_public_comments' => 'abusefilter-list-public', 'consequences' => 'abusefilter-list-consequences', 'status' => 'abusefilter-list-status', 'af_timestamp' => 'abusefilter-list-lastmodified', 'af_hidden' => 'abusefilter-list-visibility', 'af_hit_count' => 'abusefilter-list-hitcount' );
 148+
 149+ $headers = array_map( 'wfMsg', $headers );
 150+
 151+ return $headers;
 152+ }
 153+
 154+ function formatValue( $name, $value ) {
 155+ global $wgOut,$wgLang;
 156+
 157+ static $sk=null;
 158+
 159+ if (empty($sk)) {
 160+ global $wgUser;
 161+ $sk = $wgUser->getSkin();
 162+ }
 163+
 164+ $row = $this->mCurrentRow;
 165+
 166+ switch($name) {
 167+ case 'af_id':
 168+ return $sk->link( SpecialPage::getTitleFor( 'AbuseFilter', intval($value) ), intval($value) );
 169+ case 'af_public_comments':
 170+ return $wgOut->parse( $value );
 171+ case 'consequences':
 172+ return htmlspecialchars($value);
 173+ case 'status':
 174+ if ($value & 2)
 175+ return wfMsgExt( 'abusefilter-deleted', 'parseinline' );
 176+ elseif ($value & 1)
 177+ return wfMsgExt( 'abusefilter-enabled', 'parseinline' );
 178+ else
 179+ return wfMsgExt( 'abusefilter-disabled', 'parseinline' );
 180+ case 'af_hidden':
 181+ $msg = $value ? 'abusefilter-hidden' : 'abusefilter-unhidden';
 182+ return wfMsgExt( $msg, 'parseinline' );
 183+ case 'af_hit_count':
 184+ $count_display = wfMsgExt( 'abusefilter-hitcount', array( 'parseinline' ), $wgLang->formatNum( $value ) );
 185+ $link = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'AbuseLog' ), $count_display, 'wpSearchFilter='.$row->af_id );
 186+ return $link;
 187+ case 'af_timestamp':
 188+ $userLink = $sk->userLink( $row->af_user, $row->af_user_text ) . $sk->userToolLinks( $row->af_user, $row->af_user_text );
 189+ return wfMsgExt( 'abusefilter-edit-lastmod-text', array( 'replaceafter', 'parseinline' ), array( $wgLang->timeanddate($value), $userLink ) );
 190+ default:
 191+ throw new MWException( "Unknown row type $name!" );
 192+ }
 193+ }
 194+
 195+ function getDefaultSort() {
 196+ return 'af_id';
 197+ }
 198+
 199+ function isFieldSortable($name) {
 200+ $sortable_fields = array( 'af_id', 'status', 'af_hit_count', 'af_throttled', 'af_user_text', 'af_timestamp' );
 201+ return in_array( $name, $sortable_fields );
 202+ }
 203+}
\ No newline at end of file
Index: branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterView.php
@@ -0,0 +1,28 @@
 2+<?php
 3+
 4+if (!defined( 'MEDIAWIKI' ))
 5+ die();
 6+
 7+abstract class AbuseFilterView {
 8+ function __construct( $page, $params ) {
 9+ $this->mPage = $page;
 10+ $this->mParams = $params;
 11+ }
 12+
 13+ function getTitle( $subpage='' ) {
 14+ return $this->mPage->getTitle( $subpage );
 15+ }
 16+
 17+ abstract function show();
 18+
 19+ function canEdit() {
 20+ global $wgUser;
 21+ static $canEdit = 'unset';
 22+
 23+ if ($canEdit == 'unset') {
 24+ $canEdit = $wgUser->isAllowed( 'abusefilter-modify' );
 25+ }
 26+
 27+ return $canEdit;
 28+ }
 29+}
\ No newline at end of file
Index: branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterViewTools.php
@@ -0,0 +1,67 @@
 2+<?php
 3+
 4+if (!defined( 'MEDIAWIKI' ))
 5+ die();
 6+
 7+class AbuseFilterViewTools extends AbuseFilterView {
 8+ function show( ) {
 9+ global $wgRequest,$wgOut;
 10+
 11+ // Header
 12+ $wgOut->setSubTitle( wfMsg( 'abusefilter-tools-subtitle' ) );
 13+ $wgOut->addWikiMsg( 'abusefilter-tools-text' );
 14+
 15+ // Expression evaluator
 16+ $eval = '';
 17+ $eval .= Xml::textarea( 'wpTestExpr', "" );
 18+ $eval .= Xml::tags( 'p', null, Xml::element( 'input', array( 'type' => 'button', 'id' => 'mw-abusefilter-submitexpr', 'onclick' => 'doExprSubmit();', 'value' => wfMsg( 'abusefilter-tools-submitexpr' ) ) ) );
 19+ $eval .= Xml::element( 'p', array( 'id' => 'mw-abusefilter-expr-result' ), ' ' );
 20+ $eval = Xml::fieldset( wfMsg( 'abusefilter-tools-expr' ), $eval );
 21+ $wgOut->addHTML( $eval );
 22+
 23+ // Associated script
 24+ $exprScript = "function doExprSubmit()
 25+ {
 26+ var expr = document.getElementById('wpTestExpr').value;
 27+ injectSpinner( document.getElementById( 'mw-abusefilter-submitexpr' ), 'abusefilter-expr' );
 28+ sajax_do_call( 'AbuseFilter::ajaxEvaluateExpression', [expr], processExprResult );
 29+ }
 30+ function processExprResult( request ) {
 31+ var response = request.responseText;
 32+
 33+ removeSpinner( 'abusefilter-expr' );
 34+
 35+ var el = document.getElementById( 'mw-abusefilter-expr-result' );
 36+ changeText( el, response );
 37+ }
 38+ function doReautoSubmit()
 39+ {
 40+ var name = document.getElementById('reautoconfirm-user').value;
 41+ injectSpinner( document.getElementById( 'mw-abusefilter-reautoconfirmsubmit' ), 'abusefilter-reautoconfirm' );
 42+ sajax_do_call( 'AbuseFilter::ajaxReAutoconfirm', [name], processReautoconfirm );
 43+ }
 44+ function processReautoconfirm( request ) {
 45+ var response = request.responseText;
 46+
 47+ if (strlen(response)) {
 48+ jsMsg( response );
 49+ }
 50+
 51+ removeSpinner( 'abusefilter-reautoconfirm' );
 52+ }
 53+ ";
 54+
 55+ $wgOut->addInlineScript( $exprScript );
 56+
 57+ global $wgUser;
 58+
 59+ if ($wgUser->isAllowed( 'abusefilter-modify' )) {
 60+ // Hacky little box to re-enable autoconfirmed if it got disabled
 61+ $rac = '';
 62+ $rac .= Xml::inputLabel( wfMsg( 'abusefilter-tools-reautoconfirm-user' ), 'wpReAutoconfirmUser', 'reautoconfirm-user', 45 );
 63+ $rac .= Xml::element( 'input', array( 'type' => 'button', 'id' => 'mw-abusefilter-reautoconfirmsubmit', 'onclick' => 'doReautoSubmit();', 'value' => wfMsg( 'abusefilter-tools-reautoconfirm-submit' ) ) );
 64+ $rac = Xml::fieldset( wfMsg( 'abusefilter-tools-reautoconfirm' ), $rac );
 65+ $wgOut->addHTML( $rac );
 66+ }
 67+ }
 68+}
\ No newline at end of file
Index: branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterViewHistory.php
@@ -0,0 +1,134 @@
 2+<?php
 3+
 4+if (!defined( 'MEDIAWIKI' ))
 5+ die();
 6+
 7+class AbuseFilterViewHistory extends AbuseFilterView {
 8+
 9+ function __construct( $page, $params ) {
 10+ parent::__construct( $page, $params );
 11+ $this->mFilter = $page->mFilter;
 12+ }
 13+
 14+ function show() {
 15+ global $wgRequest,$wgOut;
 16+
 17+ global $wgUser;
 18+
 19+ $filter = $this->mFilter;
 20+
 21+ $sk = $wgUser->getSkin();
 22+ $wgOut->setPageTitle( wfMsg( 'abusefilter-history', $filter ) );
 23+ $backToFilter_label = wfMsgExt( 'abusefilter-history-backedit', array('parseinline') );
 24+ $backToList_label = wfMsgExt( 'abusefilter-history-backlist', array('parseinline') );
 25+ $backlinks = $sk->makeKnownLinkObj( $this->getTitle( $filter ), $backToFilter_label ) . '&nbsp;&bull;&nbsp;' .
 26+ $sk->makeKnownLinkObj( $this->getTitle( ), $backToList_label );
 27+ $wgOut->addHTML( Xml::tags( 'p', null, $backlinks ) );
 28+
 29+ $pager = new AbuseFilterHistoryPager( $filter, $this );
 30+ $table = $pager->getBody();
 31+
 32+ $wgOut->addHTML( $pager->getNavigationBar() . $table . $pager->getNavigationBar() );
 33+ }
 34+}
 35+
 36+class AbuseFilterHistoryPager extends TablePager {
 37+
 38+ function __construct( $filter, $page ) {
 39+ $this->mFilter = $filter;
 40+ $this->mPage = $page;
 41+ $this->mDefaultDirection = true;
 42+ parent::__construct();
 43+ }
 44+
 45+ function getFieldNames() {
 46+ static $headers = null;
 47+
 48+ if (!empty($headers)) {
 49+ return $headers;
 50+ }
 51+
 52+ $headers = array( 'afh_timestamp' => 'abusefilter-history-timestamp', 'afh_user_text' => 'abusefilter-history-user', 'afh_public_comments' => 'abusefilter-history-public',
 53+ 'afh_flags' => 'abusefilter-history-flags', 'afh_pattern' => 'abusefilter-history-filter', 'afh_comments' => 'abusefilter-history-comments', 'afh_actions' => 'abusefilter-history-actions' );
 54+
 55+ $headers = array_map( 'wfMsg', $headers );
 56+
 57+ return $headers;
 58+ }
 59+
 60+ function formatValue( $name, $value ) {
 61+ global $wgOut,$wgLang;
 62+
 63+ static $sk=null;
 64+
 65+ if (empty($sk)) {
 66+ global $wgUser;
 67+ $sk = $wgUser->getSkin();
 68+ }
 69+
 70+ $row = $this->mCurrentRow;
 71+
 72+ switch($name) {
 73+ case 'afh_timestamp':
 74+ $title = SpecialPage::getTitleFor( 'AbuseFilter', 'history/'.$this->mFilter.'/item/'.$row->afh_id );
 75+ return $sk->link( $title, $wgLang->timeanddate( $row->afh_timestamp ) );
 76+ case 'afh_user_text':
 77+ return $sk->userLink( $row->afh_user, $row->afh_user_text ) . ' ' . $sk->userToolLinks( $row->afh_user, $row->afh_user_text );
 78+ case 'afh_public_comments':
 79+ return $wgOut->parse( $value );
 80+ case 'afh_flags':
 81+ $flags = array_filter( explode( ',', $value ) );
 82+ $flags_display = array();
 83+ foreach( $flags as $flag ) {
 84+ $flags_display[] = wfMsg( "abusefilter-history-$flag" );
 85+ }
 86+ return implode( ', ', $flags_display );
 87+ case 'afh_pattern':
 88+ return htmlspecialchars( $wgLang->truncate( $value, 200, '...' ) );
 89+ case 'afh_comments':
 90+ return htmlspecialchars( $wgLang->truncate( $value, 200, '...' ) );
 91+ case 'afh_actions':
 92+ $actions = unserialize( $value );
 93+
 94+ $display_actions = '';
 95+
 96+ foreach( $actions as $action => $parameters ) {
 97+ $display_actions .= Xml::tags( 'li', null, wfMsgExt( 'abusefilter-history-action', array( 'parseinline' ), array($action, implode('; ', $parameters)) ) );
 98+ }
 99+ $display_actions = Xml::tags( 'ul', null, $display_actions );
 100+
 101+ return $display_actions;
 102+ }
 103+
 104+ return "Unable to format name $name\n";
 105+ }
 106+
 107+ function getQueryInfo() {
 108+ return array(
 109+ 'tables' => 'abuse_filter_history',
 110+ 'fields' => array( 'afh_timestamp', 'afh_user_text', 'afh_public_comments', 'afh_flags', 'afh_pattern', 'afh_comments', 'afh_actions', 'afh_id', 'afh_user' ),
 111+ 'conds' => array( 'afh_filter' => $this->mFilter ),
 112+ );
 113+ }
 114+
 115+ function getIndexField() {
 116+ return 'afh_timestamp';
 117+ }
 118+
 119+ function getDefaultSort() {
 120+ return 'afh_timestamp';
 121+ }
 122+
 123+ function isFieldSortable($name) {
 124+ $sortable_fields = array( 'afh_timestamp', 'afh_user_text' );
 125+ return in_array( $name, $sortable_fields );
 126+ }
 127+
 128+ /**
 129+ * Title used for self-links. Override this if you want to be able to
 130+ * use a title other than $wgTitle
 131+ */
 132+ function getTitle() {
 133+ return $this->mPage->getTitle( "history/".$this->mFilter );
 134+ }
 135+}
\ No newline at end of file
Index: branches/change-tagging/extensions/AbuseFilter/Views/AbuseFilterViewEdit.php
@@ -0,0 +1,483 @@
 2+<?php
 3+
 4+if (!defined( 'MEDIAWIKI' ))
 5+ die();
 6+
 7+class AbuseFilterViewEdit extends AbuseFilterView {
 8+
 9+ static $history_mappings = array( 'af_pattern' => 'afh_pattern', 'af_user' => 'afh_user', 'af_user_text' => 'afh_user_text', 'af_timestamp' => 'afh_timestamp', 'af_comments' => 'afh_comments', 'af_public_comments' => 'afh_public_comments', 'af_deleted' => 'afh_deleted', 'af_id' => 'afh_filter' );
 10+
 11+ function __construct( $page, $params ) {
 12+ parent::__construct( $page, $params );
 13+ $this->mFilter = $page->mFilter;
 14+ $this->mHistoryID = $page->mHistoryID;
 15+ }
 16+
 17+ function show( ) {
 18+ global $wgRequest, $wgUser, $wgOut;
 19+
 20+ $filter = $this->mFilter;
 21+ $history_id = $this->mHistoryID;
 22+ $this->mSkin = $wgUser->getSkin();
 23+
 24+ $editToken = $wgRequest->getVal( 'wpEditToken' );
 25+ $didEdit = $this->canEdit() && $wgUser->matchEditToken( $editToken, array( 'abusefilter', $filter ) );
 26+
 27+ if ($didEdit) {
 28+ // Check syntax
 29+ $syntaxerr = AbuseFilter::checkSyntax( $wgRequest->getVal( 'wpFilterRules' ) );
 30+ if ($syntaxerr !== true ) {
 31+ $wgOut->addHTML( $this->buildFilterEditor( wfMsgExt( 'abusefilter-edit-badsyntax', array( 'parseinline' ), array( $syntaxerr ) ), $filter, $history_id ) );
 32+ }
 33+
 34+ $dbw = wfGetDB( DB_MASTER );
 35+
 36+ list ($newRow, $actions) = $this->loadRequest($filter);
 37+
 38+ $newRow = get_object_vars($newRow); // Convert from object to array
 39+
 40+ // Set last modifier.
 41+ $newRow['af_timestamp'] = $dbw->timestamp( wfTimestampNow() );
 42+ $newRow['af_user'] = $wgUser->getId();
 43+ $newRow['af_user_text'] = $wgUser->getName();
 44+
 45+ $dbw->begin();
 46+
 47+ if ($filter == 'new') {
 48+ $new_id = $dbw->nextSequenceValue( 'abuse_filter_af_id_seq' );
 49+ $is_new = true;
 50+ } else {
 51+ $new_id = $this->mFilter;
 52+ $is_new = false;
 53+ }
 54+
 55+ $newRow['af_throttled'] = $newRow['af_throttled'] && !$newRow['af_enabled'];
 56+
 57+ $newRow['af_id'] = $new_id;
 58+
 59+ $dbw->replace( 'abuse_filter', array( 'af_id' ), $newRow, __METHOD__ );
 60+
 61+ if ($is_new) {
 62+ $new_id = $dbw->insertId();
 63+ }
 64+
 65+ // Actions
 66+ global $wgAbuseFilterAvailableActions;
 67+ $deadActions = array();
 68+ $actionsRows = array();
 69+ foreach( $wgAbuseFilterAvailableActions as $action ) {
 70+ // Check if it's set
 71+ $enabled = isset($actions[$action]) && (bool)$actions[$action];
 72+
 73+ if ($enabled) {
 74+ $parameters = $actions[$action]['parameters'];
 75+
 76+ $thisRow = array( 'afa_filter' => $new_id, 'afa_consequence' => $action, 'afa_parameters' => implode( "\n", $parameters ) );
 77+ $actionsRows[] = $thisRow;
 78+ } else {
 79+ $deadActions[] = $action;
 80+ }
 81+ }
 82+
 83+ // Create a history row
 84+ $afh_row = array();
 85+
 86+ foreach( self::$history_mappings as $af_col => $afh_col ) {
 87+ $afh_row[$afh_col] = $newRow[$af_col];
 88+ }
 89+
 90+ // Actions
 91+ $displayActions = array();
 92+ foreach( $actions as $action ) {
 93+ $displayActions[$action['action']] = $action['parameters'];
 94+ }
 95+ $afh_row['afh_actions'] = serialize($displayActions);
 96+
 97+ // Flags
 98+ $flags = array();
 99+ if ($newRow['af_hidden'])
 100+ $flags[] = 'hidden';
 101+ if ($newRow['af_enabled'])
 102+ $flags[] = 'enabled';
 103+ if ($newRow['af_deleted'])
 104+ $flags[] = 'deleted';
 105+
 106+ $afh_row['afh_flags'] = implode( ",", $flags );
 107+
 108+ $afh_row['afh_filter'] = $new_id;
 109+
 110+ // Do the update
 111+ $dbw->insert( 'abuse_filter_history', $afh_row, __METHOD__ );
 112+ $dbw->delete( 'abuse_filter_action', array( 'afa_filter' => $filter, 'afa_consequence' => $deadActions ), __METHOD__ );
 113+ $dbw->replace( 'abuse_filter_action', array( array( 'afa_filter', 'afa_consequence' ) ), $actionsRows, __METHOD__ );
 114+
 115+ $dbw->commit();
 116+
 117+ global $wgOut;
 118+
 119+ $wgOut->redirect( $this->getTitle()->getLocalURL( 'result=success&changedfilter='.$new_id ) );
 120+ } else {
 121+ if ($history_id) {
 122+ $wgOut->addWikiMsg( 'abusefilter-edit-oldwarning', $this->mHistoryID, $this->mFilter );
 123+ }
 124+
 125+ $wgOut->addHTML( $this->buildFilterEditor( null, $this->mFilter, $history_id ) );
 126+
 127+ if ($history_id) {
 128+ $wgOut->addWikiMsg( 'abusefilter-edit-oldwarning', $this->mHistoryID, $this->mFilter );
 129+ }
 130+ }
 131+ }
 132+
 133+ function buildFilterEditor( $error, $filter, $history_id=null ) {
 134+ if( $filter === null ) {
 135+ return false;
 136+ }
 137+
 138+ // Build the edit form
 139+ global $wgOut,$wgLang,$wgUser;
 140+ $sk = $this->mSkin;
 141+
 142+ list ($row, $actions) = $this->loadRequest($filter, $history_id);
 143+
 144+ if( !$row ) {
 145+ return false;
 146+ }
 147+
 148+ $wgOut->setSubtitle( wfMsg( 'abusefilter-edit-subtitle', $filter, $history_id ) );
 149+
 150+ if (isset($row->af_hidden) && $row->af_hidden && !$this->canEdit()) {
 151+ return wfMsg( 'abusefilter-edit-denied' );
 152+ }
 153+
 154+ $output = '';
 155+ if ($error) {
 156+ $wgOut->addHTML( "<span class=\"error\">$error</span>" );
 157+ }
 158+
 159+ $wgOut->addHTML( $sk->link( $this->getTitle(), wfMsg( 'abusefilter-history-backlist' ) ) );
 160+
 161+ $fields = array();
 162+
 163+ $fields['abusefilter-edit-id'] = $this->mFilter == 'new' ? wfMsg( 'abusefilter-edit-new' ) : $filter;
 164+ $fields['abusefilter-edit-description'] = Xml::input( 'wpFilterDescription', 45, isset( $row->af_public_comments ) ? $row->af_public_comments : '' );
 165+
 166+ // Hit count display
 167+ if( !empty($row->af_hit_count) ){
 168+ $count = (int)$row->af_hit_count;
 169+ $count_display = wfMsgExt( 'abusefilter-hitcount', array( 'parseinline' ),
 170+ $wgLang->formatNum( $count )
 171+ );
 172+ $hitCount = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'AbuseLog' ), $count_display, 'wpSearchFilter='.$row->af_id );
 173+
 174+ $fields['abusefilter-edit-hitcount'] = $hitCount;
 175+ }
 176+
 177+ if ($filter !== 'new') {
 178+ // Statistics
 179+ global $wgMemc, $wgLang;
 180+ $matches_count = $wgMemc->get( AbuseFilter::filterMatchesKey( $filter ) );
 181+ $total = $wgMemc->get( AbuseFilter::filterUsedKey() );
 182+
 183+ if ($total > 0) {
 184+ $matches_percent = sprintf( '%.2f', 100 * $matches_count / $total );
 185+ $fields['abusefilter-edit-status-label'] =
 186+ wfMsgExt( 'abusefilter-edit-status', array( 'parsemag', 'escape' ),
 187+ $wgLang->formatNum($total),
 188+ $wgLang->formatNum($matches_count),
 189+ $wgLang->formatNum($matches_percent)
 190+ );
 191+ }
 192+ }
 193+
 194+ $fields['abusefilter-edit-rules'] = $this->buildEditBox($row);
 195+ $fields['abusefilter-edit-notes'] = Xml::textarea( 'wpFilterNotes', ( isset( $row->af_comments ) ? $row->af_comments."\n" : "\n" ) );
 196+
 197+ // Build checkboxen
 198+ $checkboxes = array( 'hidden', 'enabled', 'deleted' );
 199+ $flags = '';
 200+
 201+ if (isset($row->af_throttled) && $row->af_throttled) {
 202+ global $wgAbuseFilterEmergencyDisableThreshold;
 203+ $threshold_percent = sprintf( '%.2f', $wgAbuseFilterEmergencyDisableThreshold * 100 );
 204+ $flags .= $wgOut->parse( wfMsg( 'abusefilter-edit-throttled', $wgLang->formatNum( $threshold_percent ) ) );
 205+ }
 206+
 207+ foreach( $checkboxes as $checkboxId ) {
 208+ $message = "abusefilter-edit-$checkboxId";
 209+ $dbField = "af_$checkboxId";
 210+ $postVar = "wpFilter".ucfirst($checkboxId);
 211+
 212+ $checkbox = Xml::checkLabel( wfMsg( $message ), $postVar, $postVar, isset( $row->$dbField ) ? $row->$dbField : false );
 213+ $checkbox = Xml::tags( 'p', null, $checkbox );
 214+ $flags .= $checkbox;
 215+ }
 216+ $fields['abusefilter-edit-flags'] = $flags;
 217+
 218+ if ($filter != 'new') {
 219+ // Last modification details
 220+ $user = $sk->userLink( $row->af_user, $row->af_user_text ) . $sk->userToolLinks( $row->af_user, $row->af_user_text );
 221+ $fields['abusefilter-edit-lastmod'] = wfMsgExt( 'abusefilter-edit-lastmod-text', array( 'parseinline', 'replaceafter' ), array( $wgLang->timeanddate( $row->af_timestamp ), $user ) );
 222+ $history_display = wfMsgExt( 'abusefilter-edit-viewhistory', array( 'parseinline' ) );
 223+ $fields['abusefilter-edit-history'] = $sk->makeKnownLinkObj( $this->getTitle( 'history/'.$filter ), $history_display );
 224+ }
 225+
 226+ $form = Xml::buildForm( $fields );
 227+ $form = Xml::fieldset( wfMsg( 'abusefilter-edit-main' ), $form );
 228+ $form .= Xml::fieldset( wfMsg( 'abusefilter-edit-consequences' ), $this->buildConsequenceEditor( $row, $actions ) );
 229+
 230+ if ($this->canEdit()) {
 231+ $form .= Xml::submitButton( wfMsg( 'abusefilter-edit-save' ) );
 232+ $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken( array( 'abusefilter', $filter )) );
 233+ }
 234+
 235+ $form = Xml::tags( 'form', array( 'action' => $this->getTitle( $filter )->getFullURL(), 'method' => 'POST' ), $form );
 236+
 237+ $output .= $form;
 238+
 239+ return $output;
 240+ }
 241+
 242+ function buildEditBox( $row ) {
 243+ global $wgOut;
 244+
 245+ $rules = Xml::textarea( 'wpFilterRules', ( isset( $row->af_pattern ) ? $row->af_pattern."\n" : "\n" ) );
 246+
 247+ $dropDown = array(
 248+ 'op-arithmetic' => array('+' => 'addition', '-' => 'subtraction', '*' => 'multiplication', '/' => 'divide', '%' => 'modulo', '**' => 'pow'),
 249+ 'op-comparison' => array('==' => 'equal', '!=' => 'notequal', '<' => 'lt', '>' => 'gt', '<=' => 'lte', '>=' => 'gte'),
 250+ 'op-bool' => array( '!' => 'not', '&' => 'and', '|' => 'or', '^' => 'xor' ),
 251+ 'misc' => array( 'val1 ? iftrue : iffalse' => 'ternary', 'in' => 'in', 'like' => 'like', '""' => 'stringlit', ),
 252+ 'funcs' => array( 'length(string)' => 'length', 'lcase(string)' => 'lcase', 'ccnorm(string)' => 'ccnorm', 'rmdoubles(string)' => 'rmdoubles', 'specialratio(string)' => 'specialratio', 'norm(string)' => 'norm', 'count(needle,haystack)' => 'count' ),
 253+ 'vars' => array( 'ACCOUNTNAME' => 'accountname', 'ACTION' => 'action', 'ADDED_LINES' => 'addedlines', 'EDIT_DELTA' => 'delta', 'EDIT_DIFF' => 'diff', 'NEW_SIZE' => 'newsize', 'OLD_SIZE' => 'oldsize', 'REMOVED_LINES' => 'removedlines', 'SUMMARY' => 'summary', 'ARTICLE_ARTICLEID' => 'article-id', 'ARTICLE_NAMESPACE' => 'article-ns', 'ARTICLE_TEXT' => 'article-text', 'ARTICLE_PREFIXEDTEXT' => 'article-prefixedtext', 'MOVED_FROM_ARTICLEID' => 'movedfrom-id', 'MOVED_FROM_NAMESPACE' => 'movedfrom-ns', 'MOVED_FROM_TEXT' => 'movedfrom-text', 'MOVED_FROM_PREFIXEDTEXT' => 'movedfrom-prefixedtext', 'MOVED_TO_ARTICLEID' => 'movedto-id', 'MOVED_TO_NAMESPACE' => 'movedto-ns', 'MOVED_TO_TEXT' => 'movedto-text', 'MOVED_TO_PREFIXEDTEXT' => 'movedto-prefixedtext', 'USER_EDITCOUNT' => 'user-editcount', 'USER_AGE' => 'user-age', 'USER_NAME' => 'user-name', 'USER_GROUPS' => 'user-groups', 'USER_EMAILCONFIRM' => 'user-emailconfirm'),
 254+ );
 255+
 256+ // Generate builder drop-down
 257+ $builder = '';
 258+
 259+ $builder .= Xml::option( wfMsg( "abusefilter-edit-builder-select") );
 260+
 261+ foreach( $dropDown as $group => $values ) {
 262+ $builder .= Xml::openElement( 'optgroup', array( 'label' => wfMsg( "abusefilter-edit-builder-group-$group" ) ) ) . "\n";
 263+
 264+ foreach( $values as $content => $name ) {
 265+ $builder .= Xml::option( wfMsg( "abusefilter-edit-builder-$group-$name" ), $content ) . "\n";
 266+ }
 267+
 268+ $builder .= Xml::closeElement( 'optgroup' ) . "\n";
 269+ }
 270+
 271+ $rules .= Xml::tags( 'select', array( 'id' => 'wpFilterBuilder', 'onchange' => 'addText();' ), $builder );
 272+
 273+ // Add syntax checking
 274+ $rules .= Xml::element( 'input', array( 'type' => 'button', 'onclick' => 'doSyntaxCheck()', 'value' => wfMsg( 'abusefilter-edit-check' ), 'id' => 'mw-abusefilter-syntaxcheck' ) );
 275+ $rules .= Xml::element( 'div', array( 'id' => 'mw-abusefilter-syntaxresult', 'style' => 'display: none;' ), '&nbsp;' );
 276+
 277+ // Add script
 278+ $wgOut->addInlineScript( file_get_contents(dirname(__FILE__)."/edit.js") );
 279+
 280+ return $rules;
 281+ }
 282+
 283+ function buildConsequenceEditor( $row, $actions ) {
 284+ global $wgAbuseFilterAvailableActions;
 285+ $setActions = array();
 286+ foreach( $wgAbuseFilterAvailableActions as $action ) {
 287+ $setActions[$action] = array_key_exists( $action, $actions );
 288+ }
 289+
 290+ $output = '';
 291+
 292+ // Special case: flagging - always on.
 293+ $checkbox = Xml::checkLabel( wfMsg( 'abusefilter-edit-action-flag' ), 'wpFilterActionFlag', 'wpFilterActionFlag', true, array( 'disabled' => '1' ) );
 294+ $output .= Xml::tags( 'p', null, $checkbox );
 295+
 296+ // Special case: throttling
 297+ $throttleSettings = Xml::checkLabel( wfMsg( 'abusefilter-edit-action-throttle' ), 'wpFilterActionThrottle', 'wpFilterActionThrottle', $setActions['throttle'] );
 298+ $throttleFields = array();
 299+
 300+ if ($setActions['throttle']) {
 301+ array_shift( $actions['throttle']['parameters'] );
 302+ $throttleRate = explode(',',$actions['throttle']['parameters'][0]);
 303+ $throttleCount = $throttleRate[0];
 304+ $throttlePeriod = $throttleRate[1];
 305+
 306+ $throttleGroups = implode("\n", array_slice($actions['throttle']['parameters'], 1 ) );
 307+ } else {
 308+ $throttleCount = 3;
 309+ $throttlePeriod = 60;
 310+
 311+ $throttleGroups = "user\n";
 312+ }
 313+
 314+ $throttleFields['abusefilter-edit-throttle-count'] = Xml::input( 'wpFilterThrottleCount', 20, $throttleCount );
 315+ $throttleFields['abusefilter-edit-throttle-period'] = wfMsgExt( 'abusefilter-edit-throttle-seconds', array( 'parseinline', 'replaceafter' ), array(Xml::input( 'wpFilterThrottlePeriod', 20, $throttlePeriod ) ) );
 316+ $throttleFields['abusefilter-edit-throttle-groups'] = Xml::textarea( 'wpFilterThrottleGroups', $throttleGroups."\n" );
 317+ $throttleSettings .= Xml::buildForm( $throttleFields );
 318+ $output .= Xml::tags( 'p', null, $throttleSettings );
 319+
 320+ // Special case: Warning
 321+ $checkbox = Xml::checkLabel( wfMsg( 'abusefilter-edit-action-warn' ), 'wpFilterActionWarn', 'wpFilterActionWarn', $setActions['warn'] );
 322+ $output .= Xml::tags( 'p', null, $checkbox );
 323+
 324+ $warnMsg = empty($setActions['warn']) ? 'abusefilter-warning' : $actions['warn']['parameters'][0];
 325+ $warnFields['abusefilter-edit-warn-message'] = Xml::input( 'wpFilterWarnMessage', 45, $warnMsg );
 326+ $output .= Xml::tags( 'p', null, Xml::buildForm( $warnFields ) );
 327+
 328+ // Special case: tagging
 329+ if ($setActions['tag']) {
 330+ $tags = $actions['tag']['parameters'];
 331+ } else {
 332+ $tags = array();
 333+ }
 334+
 335+ $checkbox = Xml::checkLabel( wfMsg('abusefilter-edit-action-tag'), 'wpFilterActionTag', 'wpFilterActionTag', $setActions['tag'] );
 336+ $output .= Xml::tags( 'p', null, $checkbox );
 337+
 338+ $tagFields['abusefilter-edit-tag-tag'] = Xml::textarea( 'wpFilterTags', implode( "\n", $tags ) );
 339+ $output .= Xml::tags( 'p', null, Xml::buildForm( $tagFields ) );
 340+
 341+ // The remainder are just toggles
 342+ $remainingActions = array_diff( $wgAbuseFilterAvailableActions, array( 'flag', 'throttle', 'warn', 'tag' ) );
 343+
 344+ foreach( $remainingActions as $action ) {
 345+ $message = 'abusefilter-edit-action-'.$action;
 346+ $form_field = 'wpFilterAction' . ucfirst($action);
 347+ $status = $setActions[$action];
 348+
 349+ $thisAction = Xml::checkLabel( wfMsg( $message ), $form_field, $form_field, $status );
 350+ $thisAction = Xml::tags( 'p', null, $thisAction );
 351+
 352+ $output .= $thisAction;
 353+ }
 354+
 355+ return $output;
 356+ }
 357+
 358+ function loadFilterData( $id ) {
 359+
 360+ if ($id == 'new') {
 361+ return array( new StdClass, array() );
 362+ }
 363+
 364+ $dbr = wfGetDB( DB_SLAVE );
 365+
 366+ // Load the main row
 367+ $row = $dbr->selectRow( 'abuse_filter', '*', array( 'af_id' => $id ), __METHOD__ );
 368+
 369+ if (!isset($row) || !isset($row->af_id) || !$row->af_id)
 370+ return null;
 371+
 372+ // Load the actions
 373+ $actions = array();
 374+ $res = $dbr->select( 'abuse_filter_action', '*', array( 'afa_filter' => $id), __METHOD__ );
 375+ while ( $actionRow = $dbr->fetchObject( $res ) ) {
 376+ $thisAction = array();
 377+ $thisAction['action'] = $actionRow->afa_consequence;
 378+ $thisAction['parameters'] = explode( "\n", $actionRow->afa_parameters );
 379+
 380+ $actions[$actionRow->afa_consequence] = $thisAction;
 381+ }
 382+
 383+ return array( $row, $actions );
 384+ }
 385+
 386+ function loadRequest( $filter, $history_id = null ) {
 387+ static $row = null;
 388+ static $actions = null;
 389+ global $wgRequest;
 390+
 391+ if (!is_null($actions) && !is_null($row)) {
 392+ return array($row,$actions);
 393+ } elseif ($wgRequest->wasPosted()) {
 394+ ## Nothing, we do it all later
 395+ } elseif ( $history_id ) {
 396+ return $this->loadHistoryItem( $history_id );
 397+ } else {
 398+ return $this->loadFilterData( $filter );
 399+ }
 400+
 401+ // We need some details like last editor
 402+ list($row) = $this->loadFilterData( $filter );
 403+
 404+ $textLoads = array( 'af_public_comments' => 'wpFilterDescription', 'af_pattern' => 'wpFilterRules', 'af_comments' => 'wpFilterNotes' );
 405+
 406+ foreach( $textLoads as $col => $field ) {
 407+ $row->$col = trim($wgRequest->getVal( $field ));
 408+ }
 409+
 410+ $row->af_deleted = $wgRequest->getBool( 'wpFilterDeleted' );
 411+ $row->af_enabled = $wgRequest->getBool( 'wpFilterEnabled' ) && !$row->af_deleted;
 412+ $row->af_hidden = $wgRequest->getBool( 'wpFilterHidden' );
 413+
 414+ // Actions
 415+ global $wgAbuseFilterAvailableActions;
 416+ $actions = array();
 417+ foreach( $wgAbuseFilterAvailableActions as $action ) {
 418+ // Check if it's set
 419+ $enabled = $wgRequest->getBool( 'wpFilterAction'.ucfirst($action) );
 420+
 421+ if ($enabled) {
 422+ $parameters = array();
 423+
 424+ if ($action == 'throttle') {
 425+ // Grumble grumble.
 426+ // We need to load the parameters
 427+ $throttleCount = $wgRequest->getIntOrNull( 'wpFilterThrottleCount' );
 428+ $throttlePeriod = $wgRequest->getIntOrNull( 'wpFilterThrottlePeriod' );
 429+ $throttleGroups = explode("\n", trim( $wgRequest->getText( 'wpFilterThrottleGroups' ) ) );
 430+
 431+ $parameters[0] = $this->mFilter; // For now, anyway
 432+ $parameters[1] = "$throttleCount,$throttlePeriod";
 433+ $parameters = array_merge( $parameters, $throttleGroups );
 434+ } elseif ($action == 'warn') {
 435+ $parameters[0] = $wgRequest->getVal( 'wpFilterWarnMessage' );
 436+ } elseif ($action == 'tag') {
 437+ $parameters = explode("\n", $wgRequest->getText( 'wpFilterTags' ) );
 438+ }
 439+
 440+ $thisAction = array( 'action' => $action, 'parameters' => $parameters );
 441+ $actions[$action] = $thisAction;
 442+ }
 443+ }
 444+
 445+ return array( $row, $actions );
 446+ }
 447+
 448+ function loadHistoryItem( $id ) {
 449+ $dbr = wfGetDB( DB_SLAVE );
 450+
 451+ // Load the row.
 452+ $row = $dbr->selectRow( 'abuse_filter_history', '*', array( 'afh_id' => $id ), __METHOD__ );
 453+
 454+ ## Translate into an abuse_filter row with some black magic. This is ever so slightly evil!
 455+ $af_row = new StdClass;
 456+
 457+ foreach (self::$history_mappings as $af_col => $afh_col ) {
 458+ $af_row->$af_col = $row->$afh_col;
 459+ }
 460+
 461+ ## Process flags
 462+
 463+ $af_row->af_deleted = 0;
 464+ $af_row->af_hidden = 0;
 465+ $af_row->af_enabled = 0;
 466+
 467+ $flags = explode(',', $row->afh_flags );
 468+ foreach( $flags as $flag ) {
 469+ $col_name = "af_$flag";
 470+ $af_row->$col_name = 1;
 471+ }
 472+
 473+ ## Process actions
 474+ $actions_raw = unserialize($row->afh_actions);
 475+ $actions_output = array();
 476+
 477+ foreach( $actions_raw as $action => $parameters ) {
 478+ $actions_output[$action] = array( 'action' => $action, 'parameters' => $parameters );
 479+ }
 480+
 481+
 482+ return array( $af_row, $actions_output );
 483+ }
 484+}
\ No newline at end of file

Comments

#Comment by Brion VIBBER (talk | contribs)   01:02, 23 January 2009

nummy :D

Status & tagging log