[ Index ]
 

Code source de Phorum 5.1.25

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/include/admin/ -> message_prune.php (source)

   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  


Généré le : Thu Nov 29 12:22:27 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics