[ Index ] |
|
Code source de Phorum 5.1.25 |
1 <?php 2 3 //////////////////////////////////////////////////////////////////////////////// 4 // // 5 // Copyright (C) 2007 Phorum Development Team // 6 // http://www.phorum.org // 7 // // 8 // This program is free software. You can redistribute it and/or modify // 9 // it under the terms of either the current Phorum License (viewable at // 10 // phorum.org) or the Phorum License that was distributed with this file // 11 // // 12 // This program is distributed in the hope that it will be useful, // 13 // but WITHOUT ANY WARRANTY, without even the implied warranty of // 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // 15 // // 16 // You should have received a copy of the Phorum License // 17 // along with this program. // 18 //////////////////////////////////////////////////////////////////////////////// 19 // // 20 // Author: Maurice Makaay <maurice@phorum.org> // 21 // Initial development of this message pruning interface was // 22 // generously sponsored by Juan Antonio Ruiz Zwollo. // 23 // // 24 //////////////////////////////////////////////////////////////////////////////// 25 26 if(!defined("PHORUM_ADMIN")) return; 27 28 define("ADMIN_MODULE", "message_prune"); 29 30 require_once ("./include/format_functions.php"); 31 32 // ---------------------------------------------------------------------- 33 // Possible filter rules description 34 // ---------------------------------------------------------------------- 35 36 // Build the match list for the forums. 37 $forum_info=phorum_get_forum_info(2); 38 $forum_matches = array(); 39 foreach ($forum_info as $id => $name) { 40 $forum_matches[htmlspecialchars($name)] = "message.forum_id = $id"; 41 } 42 43 $ruledefs = array 44 ( 45 "body" => array( 46 "label" => "Message body", 47 "matches" => array( 48 "contains" => "message.body = *QUERY*", 49 "does not contain" => "message.body != *QUERY*", 50 ), 51 "queryfield" => "string" 52 ), 53 54 "subject" => array( 55 "label" => "Message subject", 56 "matches" => array( 57 "is" => "message.subject = QUERY", 58 "is not" => "message.subject != QUERY", 59 "contains" => "message.subject = *QUERY*", 60 "does not contain" => "message.subject != *QUERY*", 61 ), 62 "queryfield" => "string" 63 ), 64 65 "date" => array( 66 "label" => "Message date", 67 "matches" => array( 68 "posted on" => "function:prepare_filter_date", 69 "posted on or before" => "function:prepare_filter_date", 70 "posted before" => "function:prepare_filter_date", 71 "posted after" => "function:prepare_filter_date", 72 "posted on or after" => "function:prepare_filter_date", 73 ), 74 "prepare_filter_date" => "message.datestamp", 75 "queryfield" => "date" 76 ), 77 78 "status" => array( 79 "label" => "Message status", 80 "matches" => array( 81 "approved" 82 => "message.status = ".PHORUM_STATUS_APPROVED, 83 "waiting for approval (on hold)" 84 => "message.status = ".PHORUM_STATUS_HOLD, 85 "disapproved by moderator" 86 => "message.status = ".PHORUM_STATUS_HIDDEN, 87 "hidden (on hold or disapproved)" 88 => "message.status != ".PHORUM_STATUS_APPROVED, 89 ), 90 ), 91 92 "messagetype" => array( 93 "label" => "Message type", 94 "matches" => array( 95 "thread starting messages" 96 => "message.parent_id = 0", 97 "reply messages" => "message.parent_id != 0", 98 ), 99 ), 100 101 "forum" => array( 102 "label" => "Forum", 103 "matches" => $forum_matches, 104 ), 105 106 "author" => array( 107 "label" => "Author name", 108 "matches" => array( 109 "is" => "message.author = QUERY", 110 "is not" => "message.author != QUERY", 111 "contains" => "message.author = *QUERY*", 112 "does not contain" => "message.author != *QUERY*", 113 "starts with" => "message.author = QUERY*", 114 "does not start with" => "message.author != QUERY*", 115 "ends with" => "message.author = *QUERY", 116 "does not end with" => "message.author != QUERY*", 117 ), 118 "queryfield" => "string" 119 ), 120 121 "username" => array( 122 "label" => "Author username", 123 "matches" => array( 124 "is" => "user.username = QUERY", 125 "is not" => "user.username != QUERY", 126 "contains" => "user.username = *QUERY*", 127 "does not contain" => "user.username != *QUERY*", 128 "starts with" => "user.username = QUERY*", 129 "does not start with" => "user.username != QUERY*", 130 "ends with" => "user.username = *QUERY", 131 "does not end with" => "user.username != *QUERY", 132 ), 133 "queryfield" => "string" 134 ), 135 136 "user_id" => array( 137 "label" => "Author user id", 138 "matches" => array( 139 "is" => "message.user_id = QUERY", 140 "is not" => "message.user_id != QUERY", 141 ), 142 "queryfield" => "string" 143 ), 144 145 "authortype" => array( 146 "label" => "Author type", 147 "matches" => array( 148 "registered user" => "message.user_id != 0", 149 "anonymous user" => "message.user_id = 0", 150 "moderator" => "message.moderator_post = 1", 151 "administrator" => "user.admin = 1", 152 "active user" => "user.active = " . PHORUM_USER_ACTIVE, 153 "deactivated user" => "user.active = " . PHORUM_USER_INACTIVE, 154 ) 155 ), 156 157 "ipaddress" => array( 158 "label" => "Author IP/hostname", 159 "matches" => array( 160 "is" => "message.ip = QUERY", 161 "is not" => "message.ip != QUERY", 162 "starts with" => "message.ip = QUERY*", 163 "does not start with" => "message.ip != QUERY*", 164 "ends with" => "message.ip = *QUERY", 165 "does not end with" => "message.ip != *QUERY", 166 ), 167 "queryfield" => "string" 168 ), 169 170 "threadstate" => array( 171 "label" => "Thread status", 172 "matches" => array( 173 "open for posting" => "thread.closed = 0", 174 "closed for posting" => "thread.closed = 1", 175 ), 176 ), 177 178 "threadlastpost" => array( 179 "label" => "Thread last post", 180 "matches" => array( 181 "posted on or before" => "function:prepare_filter_date", 182 "posted before" => "function:prepare_filter_date", 183 "posted after" => "function:prepare_filter_date", 184 "posted on or after" => "function:prepare_filter_date", 185 ), 186 "prepare_filter_date" => "thread.modifystamp", 187 "queryfield" => "date", 188 ), 189 ); 190 191 // ---------------------------------------------------------------------- 192 // Handle a posted form 193 // ---------------------------------------------------------------------- 194 195 $messages = null; // selected messages (based on a filter) 196 $filters = array(); // active filters 197 $filtermode = "and"; // active filter mode (and / or) 198 199 // If there are messages to delete in the post data, then delete them 200 // from the database. 201 $delete_count = 0; 202 if (isset($_POST["deletemessage"]) && is_array($_POST["deletemessage"])) 203 { 204 $msgids = array_keys($_POST["deletemessage"]); 205 $msgs = phorum_db_get_message($msgids, "message_id", true); 206 $deleted_messages = array(); 207 208 foreach ($msgs as $msg) 209 { 210 $PHORUM["forum_id"] = $msg["forum_id"]; 211 212 $delmode = $msg["parent_id"] == 0 213 ? PHORUM_DELETE_TREE 214 : PHORUM_DELETE_MESSAGE; 215 216 // A hook to allow modules to implement extra or different 217 // delete functionality. 218 list($handled, $delids, $msgid, $msg, $delmode) = phorum_hook( 219 "before_delete", 220 array(false, 0, $msg["message_id"], $msg, $delmode) 221 ); 222 223 // If the "before_delete" hook did not handle the delete action, 224 // then we have to handle it here ourselves. 225 if (! $handled) 226 { 227 // Delete the message or thread. 228 $delids = phorum_db_delete_message($msg["message_id"], $delmode); 229 230 // Cleanup the attachments for all deleted messages. 231 foreach ($delids as $delid) { 232 $files = phorum_db_get_message_file_list($delid); 233 foreach($files as $file_id=>$data) { 234 phorum_db_file_delete($file_id); 235 } 236 } 237 238 // For deleted threads, check if we have move notifications 239 // to delete. We unset the forum id, so phorum_db_get_messages() 240 // will return messages with the same thread id in 241 // other forums as well (those are the move notifications). 242 if ($delmode == PHORUM_DELETE_TREE) { 243 $forum_id = $PHORUM["forum_id"]; 244 $PHORUM["forum_id"] = 0; 245 $moved = phorum_db_get_messages($msg["message_id"]); 246 $PHORUM["forum_id"] = $forum_id; 247 foreach ($moved as $id => $data) { 248 if (isset($data["meta"]["moved"])) { 249 phorum_db_delete_message($id, PHORUM_DELETE_MESSAGE); 250 } 251 } 252 } 253 } 254 255 // Run a hook for performing custom actions after cleanup. 256 phorum_hook("delete", $delids); 257 258 // Keep track of deleted messages ids for counting the deleted 259 // messages at the end. We can't simply add the number of messages 260 // in the message array, because there might be overlap between 261 // messages and threads here. 262 foreach ($delids as $id) { 263 $delete_messages[$id] = 1; 264 } 265 } 266 267 $delete_count = count($delete_messages); 268 phorum_admin_okmsg("Deleted $delete_count message(s) from the database."); 269 } 270 271 // If a filterdesc field is in the post data, then query the database 272 // based on this filterdesc. The results will be shown later on, 273 // below the filter form. 274 if (isset($_POST["filterdesc"])) 275 { 276 // The filter rules are separated by "&" or "|" based on 277 // respectively an "AND" or an "OR" query. 278 $split = preg_split( 279 '/([&|])/', 280 $_POST["filterdesc"], 281 -1, PREG_SPLIT_DELIM_CAPTURE 282 ); 283 284 // The $split array should now contain an alternating list of 285 // rules and AND/OR specifications. Walk over the list and 286 // try to construct a metaquery to find messages based on 287 // this filter. 288 289 $meta = array(); 290 291 foreach ($split as $index => $spec) 292 { 293 // Even indexes contain a rule. 294 if ($index % 2 == 0) { 295 if (preg_match('/^(.*),(.*),(.*)$/', $spec, $m)) { 296 $field = rawurldecode($m[1]); 297 $match = rawurldecode($m[2]); 298 $query = rawurldecode($m[3]); 299 if (isset($ruledefs[$field]) && 300 isset($ruledefs[$field]["matches"][$match])) 301 { 302 $condition = $ruledefs[$field]["matches"][$match]; 303 304 // Use a custom function for filling the metaquery. 305 if (substr($condition, 0, 9) == "function:"){ 306 $func = substr($condition, 9); 307 if (!function_exists($func)) { 308 die("Internal error: filter function \"" . 309 htmlspecialchars($func) . "\" from the match ". 310 "specification for \"" . 311 htmlspecialchars($field) . "/" . 312 htmlspecialchars($match) . 313 "\" does not exist."); 314 } else { 315 $meta = call_user_func($func,$meta,$field,$match,$query); 316 } 317 } 318 // Standard metaquery addition. 319 else { 320 $meta[] = array( 321 "condition" => $condition, 322 "query" => $query 323 ); 324 } 325 326 // For rebuilding the filter form. 327 $filter = array($field, $match, $query); 328 $filters[] = $filter; 329 330 continue; 331 } 332 } 333 } 334 // Uneven indexes contain the AND/OR spec. 335 else { 336 if ($spec == '&') {$meta[]="AND"; $filtermode="and"; continue;} 337 elseif ($spec == '|') {$meta[]="OR" ; $filtermode="or" ; continue;} 338 } 339 340 die('Internal error: illegal filter specification (' . 341 'unexpected token "'.htmlspecialchars($spec).'")'); 342 } 343 344 // Let the database layer turn the metaquery into a real query 345 // and run it against the database. 346 $messages = phorum_db_metaquery_messagesearch($meta); 347 if ($messages === NULL) { 348 phorum_admin_error("Internal error: failed to run a message search"); 349 } 350 } 351 352 // Custom filter preparation for the "date" filter. 353 function prepare_filter_date($meta, $field, $match, $query) 354 { 355 $start_of_day = null; 356 $end_of_day = null; 357 358 global $ruledefs; 359 if (!$ruledefs[$field] || !isset($ruledefs[$field]["prepare_filter_date"])){ 360 die("Internal error: no date field configure in rule defs for field " . 361 '"' . htmlspecialchars($field) . '"'); 362 } 363 $dbfield = $ruledefs[$field]["prepare_filter_date"]; 364 365 $query = trim($query); 366 if (preg_match('/^(\d\d\d\d)\D(\d\d?)\D(\d\d?)$/', $query, $m)) { 367 $dy = $m[1]; $dm = $m[2]; $dd = $m[3]; 368 if ($dm >= 1 && $dm <= 31 && $dm >= 1 && $dm <= 12) { 369 // Okay, we've got a possibly valid date. Determine the 370 // start and end of this date. 371 372 // First see what our timezone offset is for the logged in user. 373 $offset = $PHORUM['tz_offset']; 374 if ($PHORUM['user_time_zone'] && 375 isset($PHORUM['user']['tz_offset']) && 376 $PHORUM['user']['tz_offset'] != -99) { 377 $offset = $PHORUM['user']['tz_offset']; 378 } 379 $offset *= 3600; 380 381 // Compute the start and end epoch time for the date. 382 $start_of_day = gmmktime(0, 0, 0, $dm, $dd, $dy) + $offset; 383 $end_of_day = gmmktime(23, 59, 59, $dm, $dd, $dy) + $offset; 384 } 385 } 386 387 if ($start_of_day !== null) 388 { 389 if ($match == "posted on") { 390 $meta[] = "("; 391 $meta[] = array( 392 "condition" => "$dbfield >= QUERY", 393 "query" => $start_of_day 394 ); 395 $meta[] = "AND"; 396 $meta[] = array( 397 "condition" => "$dbfield <= QUERY", 398 "query" => $end_of_day 399 ); 400 $meta[] = ")"; 401 } 402 elseif ($match == "posted on or before") { 403 $meta[] = array( 404 "condition" => "$dbfield <= QUERY", 405 "query" => $end_of_day 406 ); 407 } 408 elseif ($match == "posted before") { 409 $meta[] = array( 410 "condition" => "$dbfield < QUERY", 411 "query" => $start_of_day 412 ); 413 } 414 elseif ($match == "posted after") { 415 $meta[] = array( 416 "condition" => "$dbfield > QUERY", 417 "query" => $end_of_day 418 ); 419 } 420 elseif ($match == "posted on or after") { 421 $meta[] = array( 422 "condition" => "$dbfield >= QUERY", 423 "query" => $start_of_day 424 ); 425 } 426 else { 427 die("prepare_filter_date(): illegal match \"" . 428 htmlspecialchars($match) . "\""); 429 } 430 } 431 else 432 { 433 // We have to insert a condition to not disturb the query. 434 // We'll add a condition that will never match. 435 $meta[] = array( 436 "condition" => "$dbfield = 0", 437 "query" => null, 438 ); 439 } 440 441 return $meta; 442 } 443 444 // ---------------------------------------------------------------------- 445 // Javascript representation of the possible filter rules description 446 // ---------------------------------------------------------------------- 447 ?> 448 <script type="text/javascript"> 449 //<![CDATA[ 450 451 // The available filters and their configuration. 452 var ruledefs = { 453 <?php 454 $count = count($ruledefs); 455 foreach($ruledefs as $filter => $def) { 456 $count--; 457 print " '$filter':{\n" . 458 " 'label':'{$def["label"]}',\n" . 459 " 'queryfield':" . 460 (isset($def["queryfield"])?"'{$def["queryfield"]}'":"null") . 461 ",\n" . 462 " 'matches':{\n"; 463 $mcount = count($def["matches"]); 464 $idx = 0; 465 foreach ($def["matches"] as $k => $v) { 466 print " '$idx':'".addslashes($k)."'" . (--$mcount?",\n":"\n"); 467 $idx ++; 468 } 469 print " }\n" . 470 " }" . 471 ($count ? "," : "") . "\n"; 472 } ?> 473 }; 474 //]]> 475 </script> 476 477 <?php 478 // ---------------------------------------------------------------------- 479 // Display the filter form 480 // ---------------------------------------------------------------------- 481 ?> 482 483 <div class="input-form-td-break"> 484 Filter messages / threads to delete 485 </div> 486 <div class="input-form-td-message"> 487 <?php if (!count($_POST)) { ?> 488 <strong>ATTENTION!</strong><br/> 489 <div style="color:darkred"> 490 This script can delete A LOT of messages at once. So be careful 491 which messages you select for deleting. Use it at your own risk. 492 If you do not feel comfortable with this, please make a good 493 database backup before deleting any messages. 494 </div> 495 <br/> 496 The first step in deleting messages is setting up filters 497 for finding the messages that you want to delete. Please add these 498 filters below (use the plus button for adding and the minus button for 499 deleting filters). After you are done, click the "Find messages" button 500 to retrieve a list of messages that match the filters. No messages 501 will be deleted during this step.<br/> 502 <br/> 503 <?php } ?> 504 <form id="filterform" method="post" 505 action="<?php print $PHORUM["admin_http_path"] ?>" 506 onsubmit="filter.getFilterDescription()"> 507 <input type="hidden" name="module" value="<?php print ADMIN_MODULE ?>" /> 508 <input type="hidden" name="filterdesc" id="filterdesc" value="" /> 509 <div style="margin-bottom: 5px"> 510 <input id="filtermode_and" type="radio" 511 <?php if ($filtermode=='and') { ?>checked="checked"<?php } ?> 512 name="filtermode" value="and"> 513 <label for="filtermode_and">Match all of the following</label> 514 </input> 515 <input id="filtermode_or" type="radio" 516 <?php if ($filtermode=='or') { ?>checked="checked"<?php } ?> 517 name="filtermode" value="or"> 518 <label for="filtermode_or">Match any of the following</label> 519 </input> 520 </div> 521 <table class="message_prune_filtertable"> 522 <tbody id="ruleset"> 523 <!-- Only used for pushing the query field cell 100% wide. 524 It does not really work well if I try to do this from the 525 dynamic td generation below. --> 526 <tr> 527 <th></th> 528 <th></th> 529 <th style="width: 100%"></th> 530 <th></th> 531 <th></th> 532 </tr> 533 <!-- filter rules will be added dynamically at this spot in this table --> 534 <noscript> 535 <tr> 536 <td colspan="5"> 537 <strong> 538 Please, enable JavaScript in your browser. This tool 539 requires JavaScript for its operation. 540 </strong> 541 </td> 542 </tr> 543 </noscript> 544 </tbody> 545 </table> 546 <input type="submit" value="Find messages" /> 547 </form> 548 549 </div> 550 551 <?php 552 // ---------------------------------------------------------------------- 553 // Javascript filter form implementation 554 // ---------------------------------------------------------------------- 555 ?> 556 557 <script type="text/javascript"> 558 //<![CDATA[ 559 560 // Class PhorumFilterRule 561 // This class describes a single Phorum filter rule. 562 function PhorumFilterRule(conf) 563 { 564 // Check if we have all required config information. 565 if (conf == null) { 566 throw("Illegal call of PhorumFilterRule(): no config set"); 567 return; 568 } 569 if (conf.parent == null) { 570 throw("Illegal call of PhorumFilterRule(): no parent in the config"); 571 return; 572 } 573 if (conf.index == null) { 574 throw("Illegal call of PhorumFilterRule(): no index in the config"); 575 return; 576 } 577 578 // Object properties ------------------------------------------------- 579 580 // Information relating to the PhorumFilter object which created this rule. 581 this.parent = conf.parent; 582 this.index = conf.index; 583 584 // The properties that represent the rule state. 585 this.field = (conf.field ? conf.field : 'body'); 586 this.match = (conf.match ? conf.match : 'contains'); 587 this.query = (conf.query ? conf.query : ''); 588 this.query_input_type = null; 589 590 // Object methods ---------------------------------------------------- 591 592 // Method for handling actions after selecting a rule field. 593 this.onSelectFieldChange = function() 594 { 595 var idx; 596 597 // Store the current rule state. 598 idx = this.field_input.selectedIndex; 599 this.field = this.field_input.options[idx].value; 600 601 // Populate the match_input selection. 602 for (idx=this.match_input.options.length; idx>=0; idx--) { 603 this.match_input.options[idx] = null; 604 } 605 for (var id in ruledefs[this.field].matches) { 606 var o = document.createElement('option'); 607 o.value = ruledefs[this.field].matches[id]; 608 o.innerHTML = o.value; 609 if (o.value == this.match) o.selected = true; 610 this.match_input.appendChild(o); 611 } 612 613 // Clean up the current query_input if we do not need a query 614 // input or if we have to create a different type of query input. 615 if (this.query_input_type == null || 616 (ruledefs[this.field].queryfield != null && 617 ruledefs[this.field].queryfield != this.query_input_type)) { 618 if (this.query_input && this.query_input.calendar) { 619 this.query_input.calendar = null; 620 } 621 if (this.query_input && this.query_input.helptext) { 622 this.query_input_td.removeChild(this.query_input.helptext); 623 this.query_input.helptext = null; 624 } 625 if (this.query_input) { 626 this.query_input_td.removeChild(this.query_input); 627 this.query_input = null; 628 this.query_input_type = null; 629 } 630 } 631 632 // If the rule type uses a query input, then we use a separate 633 // table cell for that input. If we do not use that, we make 634 // the match_input cell span two cells. 635 if (ruledefs[this.field].queryfield == null) 636 { 637 // Take two cells for the match selection. 638 this.match_input_td.colSpan = 2; 639 640 // Remove the query input cell from the form. 641 for (var i=0; i<this.container.childNodes.length; i++) { 642 if (this.container.childNodes[i] == this.query_input_td) { 643 this.container.removeChild(this.query_input_td); 644 } 645 } 646 } 647 else 648 { 649 // Take one cell for the match selection. 650 this.match_input_td.colSpan = 1; 651 652 // Create a new query input if neccessary. 653 var create_new = false; 654 if (this.query_input_type == null) 655 { 656 this.query_input = document.createElement('input'); 657 this.query_input.ruleobj = this; 658 this.query_input.type = 'text'; 659 this.query_input.style.width='100%'; 660 this.query_input.value = this.query; 661 662 this.query_input.onkeyup = function() { 663 this.ruleobj.onQueryInputChange(this.value); 664 } 665 this.query_input.onchange = function() { 666 this.ruleobj.onQueryInputChange(this.value); 667 } 668 669 this.query_input_type = ruledefs[this.field].queryfield; 670 671 var create_new = true; 672 } 673 674 // Add the query cell + input to the table. 675 this.query_input_td.appendChild(this.query_input); 676 this.container.insertBefore( 677 this.query_input_td, 678 this.del_button_td 679 ); 680 681 // Extra options for date fields. 682 if (ruledefs[this.field].queryfield == 'date') 683 { 684 this.query_input_td.style.whiteSpace = 'nowrap'; 685 686 this.query_input.style.width = '90px'; 687 this.query_input.style.paddingLeft = '3px'; 688 this.query_input.style.fontSize = '11px'; 689 this.query_input.maxLength = 10; 690 this.query_input.style.marginRight = '6px'; 691 692 if (create_new) this.query_input.helptext=document.createTextNode("yyyy/mm/dd"); 693 this.query_input_td.style.fontSize = '11px'; 694 this.query_input_td.appendChild(this.query_input.helptext); 695 } 696 } 697 698 // Delegate further handling to onSelectMatchChange(). 699 this.onSelectMatchChange(); 700 } 701 702 // Method for handling actions after selecting a rule match. 703 this.onSelectMatchChange = function() 704 { 705 var idx; 706 707 // Store the current rule state. 708 idx = this.match_input.selectedIndex; 709 this.match = this.match_input.options[idx].value; 710 } 711 712 // Method for handling actions after changing the query input. 713 this.onQueryInputChange = function(data) { 714 this.query = data; 715 } 716 717 // Method for destroying a rule object. 718 this.destroy = function() 719 { 720 this.field_input_td.removeChild(this.field_input); 721 this.container.removeChild(this.field_input_td); 722 this.match_input_td.removeChild(this.match_input); 723 this.container.removeChild(this.match_input_td); 724 if (this.query_input) { 725 this.query_input_td.removeChild(this.query_input); 726 } 727 for (var i=0; i<this.container.childNodes.length; i++) { 728 if (this.container.childNodes[i] == this.query_input_td) { 729 this.container.removeChild(this.query_input_td); 730 } 731 } 732 this.add_button_td.removeChild(this.add_button); 733 this.container.removeChild(this.add_button_td); 734 this.del_button_td.removeChild(this.del_button); 735 this.container.removeChild(this.del_button_td); 736 737 this.add_button = null; 738 this.add_button_td = null; 739 this.del_button = null; 740 this.del_button_td = null; 741 this.field_input = null; 742 this.field_input_td = null; 743 this.match_input = null; 744 this.match_input_td = null; 745 this.query_input = null; 746 this.query_input_td = null; 747 this.container = null; 748 749 this.type = null; 750 this.match = null; 751 this.query = null; 752 } 753 754 // Build the interface ----------------------------------------------- 755 756 // Create a new table row for holding the filter rule. 757 this.container = document.createElement('tr'); 758 this.container.style.borderBottom = '1px dashed #ccc'; 759 760 // The field on which to match. 761 this.field_input = document.createElement('select'); 762 this.field_input.ruleobj = this; 763 this.field_input.onchange = function() { 764 this.ruleobj.onSelectFieldChange(); 765 } 766 767 // The type of match to use. 768 this.match_input = document.createElement('select'); 769 this.match_input.ruleobj = this; 770 this.match_input.onchange = function() { 771 this.ruleobj.onSelectMatchChange(); 772 } 773 774 // Button for adding a filter. 775 this.add_button = document.createElement('img'); 776 this.add_button.src = '<?php print $PHORUM["http_path"] ?>/images/add.png'; 777 this.add_button.style.cursor = 'pointer'; 778 this.add_button.ruleobj = this; 779 this.add_button.onclick = function() { 780 this.ruleobj.parent.addFilterRule(); 781 } 782 783 // Button for deleting a filter. 784 this.del_button = document.createElement('img'); 785 this.del_button.src = '<?php print $PHORUM["http_path"] ?>/images/delete.png'; 786 this.del_button.style.cursor = 'pointer'; 787 this.del_button.ruleobj = this; 788 this.del_button.onclick = function() { 789 this.ruleobj.parent.deleteFilterRule(this.ruleobj); 790 } 791 792 // Add cells to the table row. 793 this.field_input_td = document.createElement('td'); 794 this.field_input_td.style.padding= '5px'; 795 this.field_input_td.appendChild(this.field_input); 796 this.container.appendChild(this.field_input_td); 797 this.match_input_td = document.createElement('td'); 798 this.match_input_td.colspan = 2; 799 this.match_input_td.style.padding = '5px'; 800 this.match_input_td.appendChild(this.match_input); 801 this.container.appendChild(this.match_input_td); 802 // Will be filled and displayed when neccessary (based on fiele type). 803 this.query_input_td = document.createElement('td'); 804 this.query_input_td.style.padding = '5px'; 805 this.del_button_td = document.createElement('td'); 806 this.del_button_td.style.padding = '5px 2px'; 807 this.del_button_td.appendChild(this.del_button); 808 this.container.appendChild(this.del_button_td); 809 this.add_button_td = document.createElement('td'); 810 this.add_button_td.style.padding = '5px 5px 5px 2px'; 811 this.add_button_td.appendChild(this.add_button); 812 this.container.appendChild(this.add_button_td); 813 814 // Populate the field_input selection. 815 for (var id in ruledefs) { 816 var o = document.createElement('option'); 817 o.innerHTML = ruledefs[id]["label"]; 818 o.value = id; 819 if (o.value == this.field) o.selected = true; 820 this.field_input.appendChild(o); 821 } 822 823 // Create match select list and possibly a query 824 // input by faking a filter field selection event. 825 this.onSelectFieldChange(); 826 } 827 828 // Class PhorumFilter 829 // This class describes a set of Phorum filter rules. 830 function PhorumFilter(conf) 831 { 832 // Check if we have all required config information. 833 if (conf == null) { 834 throw("Illegal call of PhorumFilter(): no config set"); 835 return; 836 } 837 if (conf.parent == null) { 838 throw("Illegal call of PhorumFilter(): no parent in the config"); 839 return; 840 } 841 842 // Object properties ------------------------------------------------- 843 844 this.rules = new Array(); 845 this.rulecount = 0; 846 this.index = 0; 847 this.parent = conf.parent; 848 849 // Object methods ---------------------------------------------------- 850 851 this.addFilterRule = function(conf) 852 { 853 // Create a PhorumFilterRule object. 854 if (conf == null) conf = {}; 855 conf.parent = this; 856 conf.index = this.index++; 857 var ruleobj = new PhorumFilterRule(conf); 858 859 // Add the rule to the filter. 860 this.parent.appendChild(ruleobj.container); 861 this.rules[ruleobj.index] = ruleobj; 862 863 this.rulecount ++; 864 } 865 866 this.deleteFilterRule = function(ruleobj) 867 { 868 // Do not delete the last rule. 869 if (this.rulecount == 1) return; 870 871 // Delete the rule from the filter. 872 this.parent.removeChild(ruleobj.container); 873 this.rules[ruleobj.index] = null; 874 ruleobj.destroy(); 875 876 this.rulecount --; 877 } 878 879 // Construct a textual description of the filter. 880 this.getFilterDescription = function() 881 { 882 var filterdesc = ''; 883 884 // Determine the glue symbol to use. 885 // & for AND matches, | for OR matches 886 var glue = document.getElementById('filtermode_or').checked?'|':'&'; 887 888 // Walk over all available filters and create a 889 // textual filter config line for them. 890 for (var i = 0 ; i < this.index; i++) { 891 if (this.rules[i] == null) continue; 892 var rule = this.rules[i]; 893 if (filterdesc != '') filterdesc += glue; 894 filterdesc += escape(rule.field) + "," + 895 escape(rule.match) + "," + 896 escape(rule.query); 897 } 898 899 document.getElementById('filterdesc').value = filterdesc; 900 document.getElementById('filterform').submit(); 901 } 902 } 903 904 // Create the filter object. 905 var filter = new PhorumFilter({ 906 "parent": document.getElementById("ruleset") 907 }); 908 909 // Add filter rules. 910 <?php 911 if (count($filters)) { 912 foreach ($filters as $filter) { 913 print "filter.addFilterRule({\n" . 914 " 'field': '".addslashes($filter[0])."',\n" . 915 " 'match': '".addslashes($filter[1])."',\n" . 916 " 'query': '".addslashes($filter[2])."'\n" . 917 "});\n"; 918 } 919 } else { 920 print "filter.addFilterRule();\n"; 921 } 922 ?> 923 924 //]]> 925 </script> 926 927 <?php 928 // ---------------------------------------------------------------------- 929 // Show selected messages. 930 // ---------------------------------------------------------------------- 931 932 if (isset($messages) && is_array($messages)) 933 { 934 if (count($messages)) { ?> 935 <script type="text/javascript"> 936 //<![CDATA[ 937 938 function toggle_msginfo(id) 939 { 940 var d = document.getElementById('msginfo_'+id); 941 d.style.display = d.style.display != 'block' ? 'block' : 'none'; 942 return false; 943 } 944 945 function select_all_messages() 946 { 947 var f = document.getElementById('selectform'); 948 for (var i = 0; i < f.elements.length; i++) { 949 if (f.elements[i].type == 'checkbox') { 950 f.elements[i].checked = true; 951 } 952 } 953 return false; 954 } 955 956 function delete_selected_messages() 957 { 958 var count = 0; 959 var f = document.getElementById('selectform'); 960 for (var i = 0; i < f.elements.length; i++) { 961 if (f.elements[i].type == 'checkbox' && 962 f.elements[i].checked) { 963 count ++; 964 } 965 } 966 if (count == 0) { 967 alert('Please select the message(s) that you want to delete.'); 968 return false; 969 } 970 971 return confirm( 972 'Delete the ' + count + ' selected message(s) ' + 973 '/ thread(s) from the database?' 974 ); 975 } 976 977 //]]> 978 </script> 979 980 <form id="selectform" method="post" 981 action="<?php print $PHORUM["admin_http_path"] ?>"> 982 <input type="hidden" name="module" value="<?php print ADMIN_MODULE ?>" /> 983 <input type="hidden" name="filterdesc" id="filterdesc" value="<?php 984 // Remember the filter description if one is available 985 // (should be at this point). 986 if (isset($_POST["filterdesc"])) { 987 print htmlspecialchars($_POST["filterdesc"]); 988 } 989 ?>" /> 990 991 <div class="input-form-td-break" style="margin-bottom: 10px"> 992 Select messages / threads to delete 993 (<?php print count($messages) ?> 994 result<?php if (count($messages)!=1) print "s" ?> found) 995 </div> 996 997 <div class="input-form-td-message"> 998 Here you see all messages and threads that were found, based on the 999 above filters. You can still modify the filters if you like. 1000 To delete messages or threads, you have to check the checkboxes in front 1001 of them and click on "Delete selected". If you need more info about a 1002 certain item, then click on the subject for expanding the view.<br/> 1003 <br/> 1004 The icon and color tell you if are handling a 1005 <span style="color:#009">message</span> 1006 (<img align="top" src="<?php print $PHORUM["http_path"] ?>/images/comment.png"/>) 1007 or a <span style="color:#c30">thread</span> 1008 (<img align="top" src="<?php print $PHORUM["http_path"] ?>/images/comments.png"/>). 1009 <br/> 1010 <br/> 1011 <?php if (count($messages) > 10) { ?> 1012 <input type="button" value="Select all" 1013 onclick="return select_all_messages()" /> 1014 <input type="submit" value="Delete selected" 1015 onclick="return delete_selected_messages()" /> 1016 <br/><br/> 1017 <?php } ?> 1018 <table style="width:96%; border-collapse:collapse"> 1019 <?php 1020 1021 // Add the messages to the form. 1022 foreach ($messages as $id => $data) { 1023 $icon = $data["parent_id"] == 0 ? "comments.png" : "comment.png"; 1024 $color = $data["parent_id"] == 0 ? "#c30" : "#009"; 1025 $alt = $data["parent_id"] == 0 ? "thread" : "message"; 1026 1027 $strippedbody = nl2br(htmlspecialchars($data["body"])); 1028 1029 ?> 1030 <tr> 1031 <td valign="top" style="border-bottom:1px dashed #ccc"> 1032 <input type="checkbox" name="deletemessage[<?php print $id ?>]"/> 1033 </td> 1034 <td valign="top" style="width:100%;border-bottom:1px dashed #ccc"> 1035 <span style="float:right"> 1036 <?php print htmlspecialchars($data["author"]) ?> 1037 <?php print phorum_date("%Y/%m/%d", $data["datestamp"]) ?> 1038 </span> 1039 <img align="top" 1040 title="<?php print $alt ?>" alt="<?php print $alt ?>" 1041 src="<?php print $PHORUM["http_path"]."/images/".$icon ?>"/> 1042 <a style="text-decoration: none" href="#" 1043 onclick="return toggle_msginfo(<?php print $id ?>)"> 1044 <span style="color:<?php print $color?>"> 1045 <?php print htmlspecialchars($data["subject"]) ?> 1046 </span> 1047 </a> 1048 <div class="message_prune_msginfo" id="msginfo_<?php print $id ?>"> 1049 <?php 1050 if ($data["user_id"]) { 1051 print "Posted by authenticated user \"". 1052 htmlspecialchars($data["user_username"]) . 1053 "\" (user_id ".$data["user_id"].")<br/>"; 1054 } 1055 print "Date and time: " . phorum_date("%Y/%m/%d %H:%M:%S", $data["datestamp"]) . "<br/>"; 1056 // Might not be available (for announcements). 1057 // I won't put a lot of stuff in here for handling announcements, 1058 // because 5.2 handles them differently than 5.1. 1059 if (isset($forum_info[$data["forum_id"]])) { 1060 print "Forum: ". $forum_info[$data["forum_id"]] . "<br/>"; 1061 } 1062 if ($data["parent_id"] == 0) { 1063 print "Messages in this thread: {$data["thread_count"]}<br/>"; 1064 if ($data["thread_count"] > 1) { 1065 print "Thread's last post: " . 1066 phorum_date("%Y/%m/%d %H:%M:%S", $data["thread_modifystamp"]) . "<br/>"; 1067 } 1068 } 1069 ?> 1070 <div class="message_prune_msginfo_body"> 1071 <?php print $strippedbody ?> 1072 </div> 1073 </div> 1074 </td> 1075 </tr> <?php 1076 } ?> 1077 1078 </table> 1079 <br/> 1080 <input type="button" value="Select all" 1081 onclick="return select_all_messages()" /> 1082 <input type="submit" value="Delete selected" 1083 onclick="return delete_selected_messages()" /> 1084 </div> 1085 </form> 1086 <?php 1087 // count($messages) == 0 1088 } else { ?> 1089 <div class="input-form-td-break" style="margin-bottom: 10px"> 1090 No messages were found 1091 </div> 1092 <div class="input-form-td-message"> 1093 Your current filter does not match any message in your database. 1094 </div> 1095 1096 <?php 1097 } 1098 } 1099 ?> 1100 1101 1102
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 12:22:27 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |