[ Index ] |
PHP Cross Reference of MyBB 1.8.30 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * MyBB 1.8 4 * Copyright 2014 MyBB Group, All Rights Reserved 5 * 6 * Website: http://www.mybb.com 7 * License: http://www.mybb.com/about/license 8 * 9 */ 10 11 class Moderation 12 { 13 /** 14 * Close one or more threads 15 * 16 * @param array|int $tids Thread ID(s) 17 * @return boolean true 18 */ 19 function close_threads($tids) 20 { 21 global $db, $plugins; 22 23 if(!is_array($tids)) 24 { 25 $tids = array($tids); 26 } 27 28 // Make sure we only have valid values 29 $tids = array_map('intval', $tids); 30 31 $plugins->run_hooks("class_moderation_close_threads", $tids); 32 33 $tid_list = implode(',', $tids); 34 35 $openthread = array( 36 "closed" => 1, 37 ); 38 $db->update_query("threads", $openthread, "tid IN ($tid_list) AND closed NOT LIKE 'moved|%'"); 39 40 return true; 41 } 42 43 /** 44 * Open one or more threads 45 * 46 * @param array|int $tids Thread ID(s) 47 * @return boolean 48 */ 49 50 function open_threads($tids) 51 { 52 global $db, $plugins; 53 54 if(!is_array($tids)) 55 { 56 $tids = array($tids); 57 } 58 59 if(empty($tids)) 60 { 61 return false; 62 } 63 64 // Make sure we only have valid values 65 $tids = array_map('intval', $tids); 66 67 $plugins->run_hooks("class_moderation_open_threads", $tids); 68 69 $tid_list = implode(',', $tids); 70 71 $closethread = array( 72 "closed" => 0, 73 ); 74 $db->update_query("threads", $closethread, "tid IN ($tid_list)"); 75 76 return true; 77 } 78 79 /** 80 * Stick one or more threads 81 * 82 * @param array|int $tids Thread ID(s) 83 * @return boolean 84 */ 85 function stick_threads($tids) 86 { 87 global $db, $plugins; 88 89 if(!is_array($tids)) 90 { 91 $tids = array($tids); 92 } 93 94 if(empty($tids)) 95 { 96 return false; 97 } 98 99 // Make sure we only have valid values 100 $tids = array_map('intval', $tids); 101 102 $plugins->run_hooks("class_moderation_stick_threads", $tids); 103 104 $tid_list = implode(',', $tids); 105 106 $stickthread = array( 107 "sticky" => 1, 108 ); 109 $db->update_query("threads", $stickthread, "tid IN ($tid_list)"); 110 111 return true; 112 } 113 114 /** 115 * Unstick one or more thread 116 * 117 * @param array|int $tids Thread ID(s) 118 * @return boolean 119 */ 120 function unstick_threads($tids) 121 { 122 global $db, $plugins; 123 124 if(!is_array($tids)) 125 { 126 $tids = array($tids); 127 } 128 129 if(empty($tids)) 130 { 131 return false; 132 } 133 134 // Make sure we only have valid values 135 $tids = array_map('intval', $tids); 136 137 $plugins->run_hooks("class_moderation_unstick_threads", $tids); 138 139 $tid_list = implode(',', $tids); 140 141 $unstickthread = array( 142 "sticky" => 0, 143 ); 144 $db->update_query("threads", $unstickthread, "tid IN ($tid_list)"); 145 146 return true; 147 } 148 149 /** 150 * Remove redirects that redirect to the specified thread 151 * 152 * @param int $tid Thread ID of the thread 153 * @return boolean 154 */ 155 function remove_redirects($tid) 156 { 157 global $db, $plugins; 158 159 $plugins->run_hooks("class_moderation_remove_redirects", $tid); 160 161 // Delete the redirects 162 $tid = (int)$tid; 163 if(empty($tid)) 164 { 165 return false; 166 } 167 168 $query = $db->simple_select('threads', 'tid', "closed='moved|$tid'"); 169 while($redirect_tid = $db->fetch_field($query, 'tid')) 170 { 171 $this->delete_thread($redirect_tid); 172 } 173 174 return true; 175 } 176 177 /** 178 * Delete a thread 179 * 180 * @param int $tid Thread ID of the thread 181 * @return boolean 182 */ 183 function delete_thread($tid) 184 { 185 global $db, $cache, $plugins; 186 187 $tid = (int)$tid; 188 189 $plugins->run_hooks("class_moderation_delete_thread_start", $tid); 190 191 $thread = get_thread($tid); 192 if(!$thread) 193 { 194 return false; 195 } 196 $forum = get_forum($thread['fid']); 197 198 $userposts = array(); 199 200 // Find the pid, uid, visibility, and forum post count status 201 $query = $db->simple_select('posts', 'pid, uid, visible', "tid='{$tid}'"); 202 $pids = array(); 203 $num_unapproved_posts = $num_approved_posts = $num_deleted_posts = 0; 204 while($post = $db->fetch_array($query)) 205 { 206 $pids[] = $post['pid']; 207 208 if(!function_exists("remove_attachments")) 209 { 210 require_once MYBB_ROOT."inc/functions_upload.php"; 211 } 212 213 // Remove attachments 214 remove_attachments($post['pid']); 215 216 // If the post is unapproved, count it! 217 if(($post['visible'] == 0 && $thread['visible'] != -1) || $thread['visible'] == 0) 218 { 219 $num_unapproved_posts++; 220 } 221 elseif($post['visible'] == -1 || $thread['visible'] == -1) 222 { 223 $num_deleted_posts++; 224 } 225 else 226 { 227 $num_approved_posts++; 228 229 // Count the post counts for each user to be subtracted 230 if($forum['usepostcounts'] != 0) 231 { 232 if(!isset($userposts[$post['uid']]['num_posts'])) 233 { 234 $userposts[$post['uid']]['num_posts'] = 0; 235 } 236 ++$userposts[$post['uid']]['num_posts']; 237 } 238 } 239 } 240 241 if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') 242 { 243 if(!isset($userposts[$thread['uid']]['num_threads'])) 244 { 245 $userposts[$thread['uid']]['num_threads'] = 0; 246 } 247 ++$userposts[$thread['uid']]['num_threads']; 248 } 249 250 // Remove post count from users 251 if($thread['visible'] == 1) 252 { 253 if(!empty($userposts)) 254 { 255 foreach($userposts as $uid => $subtract) 256 { 257 $update_array = array(); 258 259 if(isset($subtract['num_posts'])) 260 { 261 $update_array['postnum'] = "-{$subtract['num_posts']}"; 262 } 263 264 if(isset($subtract['num_threads'])) 265 { 266 $update_array['threadnum'] = "-{$subtract['num_threads']}"; 267 } 268 269 update_user_counters($uid, $update_array); 270 } 271 } 272 } 273 // Delete posts and their attachments 274 if(!empty($pids)) 275 { 276 $pids = implode(',', $pids); 277 $db->delete_query("posts", "pid IN ($pids)"); 278 $db->delete_query("attachments", "pid IN ($pids)"); 279 $db->delete_query("reportedcontent", "id IN ($pids) AND (type = 'post' OR type = '')"); 280 } 281 282 // Delete threads, redirects, subscriptions, polls, and poll votes 283 $db->delete_query("threads", "tid='$tid'"); 284 $query = $db->simple_select('threads', 'tid', "closed='moved|$tid'"); 285 while($redirect_tid = $db->fetch_field($query, 'tid')) 286 { 287 $this->delete_thread($redirect_tid); 288 } 289 $db->delete_query("threadsubscriptions", "tid='$tid'"); 290 $db->delete_query("polls", "tid='$tid'"); 291 $db->delete_query("pollvotes", "pid='".$thread['poll']."'"); 292 $db->delete_query("threadsread", "tid='$tid'"); 293 $db->delete_query("threadratings", "tid='$tid'"); 294 295 $updated_counters = array( 296 "posts" => "-{$num_approved_posts}", 297 "unapprovedposts" => "-{$num_unapproved_posts}", 298 "deletedposts" => "-{$num_deleted_posts}" 299 ); 300 301 if($thread['visible'] == 1) 302 { 303 $updated_counters['threads'] = -1; 304 } 305 elseif($thread['visible'] == -1) 306 { 307 $updated_counters['deletedthreads'] = -1; 308 } 309 else 310 { 311 $updated_counters['unapprovedthreads'] = -1; 312 } 313 314 if(strpos($thread['closed'], 'moved|') !== false) 315 { 316 // Redirect 317 if($thread['visible'] == 1) 318 { 319 $updated_counters['posts'] = -1; 320 } 321 elseif($thread['visible'] == -1) 322 { 323 $updated_counters['deletedposts'] = -1; 324 } 325 else 326 { 327 $updated_counters['unapprovedposts'] = -1; 328 } 329 } 330 331 // Update forum count 332 update_forum_counters($thread['fid'], $updated_counters); 333 update_forum_lastpost($thread['fid']); 334 mark_reports($tid, 'thread'); 335 336 $plugins->run_hooks("class_moderation_delete_thread", $tid); 337 338 return true; 339 } 340 341 /** 342 * Delete a poll 343 * 344 * @param int $pid Poll id 345 * @return boolean 346 */ 347 function delete_poll($pid) 348 { 349 global $db, $plugins; 350 351 $pid = (int)$pid; 352 353 if(empty($pid)) 354 { 355 return false; 356 } 357 358 $plugins->run_hooks("class_moderation_delete_poll", $pid); 359 360 $db->delete_query("polls", "pid='$pid'"); 361 $db->delete_query("pollvotes", "pid='$pid'"); 362 $pollarray = array( 363 'poll' => '0', 364 ); 365 $db->update_query("threads", $pollarray, "poll='$pid'"); 366 367 return true; 368 } 369 370 /** 371 * Approve one or more threads 372 * 373 * @param array|int $tids Thread ID(s) 374 * @return boolean 375 */ 376 function approve_threads($tids) 377 { 378 global $db, $cache, $plugins; 379 380 if(!is_array($tids)) 381 { 382 $tids = array($tids); 383 } 384 385 if(empty($tids)) 386 { 387 return false; 388 } 389 390 // Make sure we only have valid values 391 $tids = array_map('intval', $tids); 392 393 $tid_list = $forum_counters = $user_counters = $posts_to_approve = array(); 394 395 $tids_list = implode(",", $tids); 396 $query = $db->simple_select("threads", "*", "tid IN ($tids_list)"); 397 398 while($thread = $db->fetch_array($query)) 399 { 400 if($thread['visible'] == 1 || $thread['visible'] == -1) 401 { 402 continue; 403 } 404 $tid_list[] = $thread['tid']; 405 406 $forum = get_forum($thread['fid']); 407 408 if(!isset($forum_counters[$forum['fid']])) 409 { 410 $forum_counters[$forum['fid']] = array( 411 'num_posts' => 0, 412 'num_threads' => 0, 413 'num_deleted_posts' => 0, 414 'num_unapproved_posts' => 0 415 ); 416 } 417 418 if(!isset($user_counters[$thread['uid']])) 419 { 420 $user_counters[$thread['uid']] = array( 421 'num_posts' => 0, 422 'num_threads' => 0 423 ); 424 } 425 426 ++$forum_counters[$forum['fid']]['num_threads']; 427 $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Remove implied visible from count 428 $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['deletedposts']; 429 $forum_counters[$forum['fid']]['num_unapproved_posts'] += $thread['deletedposts']+$thread['replies']+1; 430 431 if($forum['usepostcounts'] != 0) 432 { 433 // On approving thread restore user post counts 434 $query2 = $db->simple_select("posts", "COUNT(pid) as posts, uid", "tid='{$thread['tid']}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid"); 435 while($counter = $db->fetch_array($query2)) 436 { 437 $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; 438 } 439 } 440 441 if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') 442 { 443 ++$user_counters[$thread['uid']]['num_threads']; 444 } 445 446 $posts_to_approve[] = $thread['firstpost']; 447 } 448 449 if(!empty($tid_list)) 450 { 451 $tid_moved_list = ""; 452 $comma = ""; 453 foreach($tid_list as $tid) 454 { 455 $tid_moved_list .= "{$comma}'moved|{$tid}'"; 456 $comma = ","; 457 } 458 $tid_list = implode(',', $tid_list); 459 $approve = array( 460 "visible" => 1 461 ); 462 $db->update_query("threads", $approve, "tid IN ($tid_list)"); 463 // Approve redirects, too 464 $redirect_tids = array(); 465 $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); 466 while($redirect_tid = $db->fetch_field($query, 'tid')) 467 { 468 $redirect_tids[] = $redirect_tid; 469 } 470 if(!empty($redirect_tids)) 471 { 472 $this->approve_threads($redirect_tids); 473 } 474 if(!empty($posts_to_approve)) 475 { 476 $db->update_query("posts", $approve, "pid IN (".implode(',', $posts_to_approve).")"); 477 } 478 479 $plugins->run_hooks("class_moderation_approve_threads", $tids); 480 481 if(!empty($forum_counters)) 482 { 483 foreach($forum_counters as $fid => $counters) 484 { 485 // Update stats 486 $update_array = array( 487 "threads" => "+{$counters['num_threads']}", 488 "unapprovedthreads" => "-{$counters['num_threads']}", 489 "posts" => "+{$counters['num_posts']}", 490 "unapprovedposts" => "-{$counters['num_unapproved_posts']}", 491 "deletedposts" => "+{$counters['num_deleted_posts']}" 492 ); 493 update_forum_counters($fid, $update_array); 494 update_forum_lastpost($fid); 495 } 496 } 497 498 if(!empty($user_counters)) 499 { 500 foreach($user_counters as $uid => $counters) 501 { 502 $update_array = array( 503 "postnum" => "+{$counters['num_posts']}", 504 "threadnum" => "+{$counters['num_threads']}", 505 ); 506 update_user_counters($uid, $update_array); 507 } 508 } 509 } 510 return true; 511 } 512 513 /** 514 * Unapprove one or more threads 515 * 516 * @param array|int $tids Thread ID(s) 517 * @return boolean 518 */ 519 function unapprove_threads($tids) 520 { 521 global $db, $cache, $plugins; 522 523 if(!is_array($tids)) 524 { 525 $tids = array($tids); 526 } 527 528 if(empty($tids)) 529 { 530 return false; 531 } 532 533 // Make sure we only have valid values 534 $tids = array_map('intval', $tids); 535 536 $tid_list = implode(',', $tids); 537 $tid_moved_list = ""; 538 $comma = ""; 539 foreach($tids as $tid) 540 { 541 $tid_moved_list .= "{$comma}'moved|{$tid}'"; 542 $comma = ","; 543 } 544 545 $forum_counters = $user_counters = $posts_to_unapprove = array(); 546 547 $tids_list = implode(",", $tids); 548 $query = $db->simple_select("threads", "*", "tid IN ($tids_list)"); 549 550 while($thread = $db->fetch_array($query)) 551 { 552 $forum = get_forum($thread['fid']); 553 554 if($thread['visible'] == 1 || $thread['visible'] == -1) 555 { 556 if(!isset($forum_counters[$forum['fid']])) 557 { 558 $forum_counters[$forum['fid']] = array( 559 'num_threads' => 0, 560 'num_posts' => 0, 561 'num_unapprovedthreads' => 0, 562 'num_unapprovedposts' => 0, 563 'num_deletedthreads' => 0, 564 'num_deletedposts' => 0 565 ); 566 } 567 568 if(!isset($user_counters[$thread['uid']])) 569 { 570 $user_counters[$thread['uid']] = array( 571 'num_posts' => 0, 572 'num_threads' => 0 573 ); 574 } 575 576 ++$forum_counters[$forum['fid']]['num_unapprovedthreads']; 577 $forum_counters[$forum['fid']]['num_unapprovedposts'] += $thread['replies']+$thread['deletedposts']+1; 578 579 if($thread['visible'] == 1) 580 { 581 ++$forum_counters[$forum['fid']]['num_threads']; 582 $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Add implied invisible to count 583 $forum_counters[$forum['fid']]['num_deletedposts'] += $thread['deletedposts']; 584 } 585 else 586 { 587 ++$forum_counters[$forum['fid']]['num_deletedthreads']; 588 $forum_counters[$forum['fid']]['num_deletedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Add implied invisible to count 589 $forum_counters[$forum['fid']]['num_unapprovedposts'] += $thread['unapprovedposts']; 590 } 591 592 // On unapproving thread update user post counts 593 if($thread['visible'] == 1 && $forum['usepostcounts'] != 0) 594 { 595 $query2 = $db->simple_select("posts", "COUNT(pid) AS posts, uid", "tid='{$thread['tid']}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid"); 596 while($counter = $db->fetch_array($query2)) 597 { 598 $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; 599 } 600 } 601 602 if($thread['visible'] == 1 && $forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') 603 { 604 ++$user_counters[$thread['uid']]['num_threads']; 605 } 606 607 } 608 $posts_to_unapprove[] = $thread['firstpost']; 609 } 610 611 $approve = array( 612 "visible" => 0 613 ); 614 $db->update_query("threads", $approve, "tid IN ($tid_list)"); 615 // Unapprove redirects, too 616 $redirect_tids = array(); 617 $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); 618 while($redirect_tid = $db->fetch_field($query, 'tid')) 619 { 620 $redirect_tids[] = $redirect_tid; 621 } 622 if(!empty($redirect_tids)) 623 { 624 $this->unapprove_threads($redirect_tids); 625 } 626 if(!empty($posts_to_unapprove)) 627 { 628 $db->update_query("posts", $approve, "pid IN (".implode(',', $posts_to_unapprove).")"); 629 } 630 631 $plugins->run_hooks("class_moderation_unapprove_threads", $tids); 632 633 if(!empty($forum_counters)) 634 { 635 foreach($forum_counters as $fid => $counters) 636 { 637 // Update stats 638 $update_array = array( 639 "threads" => "-{$counters['num_threads']}", 640 "unapprovedthreads" => "+{$counters['num_unapprovedthreads']}", 641 "posts" => "-{$counters['num_posts']}", 642 "unapprovedposts" => "+{$counters['num_unapprovedposts']}", 643 "deletedthreads" => "-{$counters['num_deletedthreads']}", 644 "deletedposts" => "-{$counters['num_deletedposts']}" 645 ); 646 update_forum_counters($fid, $update_array); 647 update_forum_lastpost($fid); 648 } 649 } 650 651 if(!empty($user_counters)) 652 { 653 foreach($user_counters as $uid => $counters) 654 { 655 $update_array = array( 656 "postnum" => "-{$counters['num_posts']}", 657 "threadnum" => "-{$counters['num_threads']}", 658 ); 659 update_user_counters($uid, $update_array); 660 } 661 } 662 663 return true; 664 } 665 666 /** 667 * Delete a specific post 668 * 669 * @param int $pid Post ID 670 * @return boolean 671 */ 672 function delete_post($pid) 673 { 674 global $db, $cache, $plugins; 675 676 $pid = $plugins->run_hooks("class_moderation_delete_post_start", $pid); 677 // Get pid, uid, fid, tid, visibility, forum post count status of post 678 $pid = (int)$pid; 679 $query = $db->query(" 680 SELECT p.pid, p.uid, p.fid, p.tid, p.visible, t.visible as threadvisible 681 FROM ".TABLE_PREFIX."posts p 682 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 683 WHERE p.pid='$pid' 684 "); 685 $post = $db->fetch_array($query); 686 if(!$post) 687 { 688 return false; 689 } 690 691 $forum = get_forum($post['fid']); 692 // If post counts enabled in this forum and it hasn't already been unapproved, remove 1 693 if($forum['usepostcounts'] != 0 && $post['visible'] != -1 && $post['visible'] != 0 && $post['threadvisible'] != 0 && $post['threadvisible'] != -1) 694 { 695 update_user_counters($post['uid'], array('postnum' => "-1")); 696 } 697 698 if(!function_exists("remove_attachments")) 699 { 700 require MYBB_ROOT."inc/functions_upload.php"; 701 } 702 703 // Remove attachments 704 remove_attachments($pid); 705 706 // Delete the post 707 $db->delete_query("posts", "pid='$pid'"); 708 709 // Remove any reports attached to this post 710 $db->delete_query("reportedcontent", "id='{$pid}' AND (type = 'post' OR type = '')"); 711 712 // Update unapproved post count 713 if($post['visible'] == 0) 714 { 715 $update_array = array( 716 "unapprovedposts" => "-1" 717 ); 718 } 719 elseif($post['visible'] == -1) 720 { 721 $update_array = array( 722 "deletedposts" => "-1" 723 ); 724 } 725 else 726 { 727 $update_array = array( 728 "replies" => "-1" 729 ); 730 } 731 732 $plugins->run_hooks("class_moderation_delete_post", $post['pid']); 733 734 update_thread_counters($post['tid'], $update_array); 735 update_last_post($post['tid']); 736 737 // Update unapproved post count 738 if(($post['visible'] == 0 && $post['threadvisible'] != -1) || $post['threadvisible'] == 0) 739 { 740 $update_array = array( 741 "unapprovedposts" => "-1" 742 ); 743 } 744 elseif($post['visible'] == -1 || $post['threadvisible'] == -1) 745 { 746 $update_array = array( 747 "deletedposts" => "-1" 748 ); 749 } 750 else 751 { 752 $update_array = array( 753 "posts" => "-1" 754 ); 755 } 756 757 update_forum_counters($post['fid'], $update_array); 758 update_forum_lastpost($post['fid']); 759 760 return true; 761 } 762 763 /** 764 * Merge posts within thread 765 * 766 * @param array $pids Post IDs to be merged 767 * @param int $tid Thread ID (Set to 0 if posts from multiple threads are selected) 768 * @return int ID of the post into which all other posts are merged 769 */ 770 function merge_posts($pids=array(), $tid=0, $sep="new_line") 771 { 772 global $db, $plugins; 773 774 // Make sure we only have valid values 775 $pids = array_map('intval', $pids); 776 777 if(empty($pids) || count($pids) < 2) 778 { 779 return false; 780 } 781 782 $pidin = implode(',', $pids); 783 $attachment_count = 0; 784 785 $first = 1; 786 // Get the messages to be merged 787 $query = $db->query(" 788 SELECT p.pid, p.uid, p.fid, p.tid, p.visible, p.message, t.visible AS threadvisible, t.replies AS threadreplies, t.firstpost AS threadfirstpost, t.unapprovedposts AS threadunapprovedposts, COUNT(a.aid) AS attachmentcount 789 FROM ".TABLE_PREFIX."posts p 790 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 791 LEFT JOIN ".TABLE_PREFIX."attachments a ON (a.pid=p.pid AND a.visible=1) 792 WHERE p.pid IN($pidin) 793 GROUP BY p.pid 794 ORDER BY p.dateline ASC, p.pid ASC 795 "); 796 $message = ''; 797 $threads = $forum_counters = $thread_counters = $user_counters = array(); 798 while($post = $db->fetch_array($query)) 799 { 800 $threads[$post['tid']] = $post['tid']; 801 if(!isset($thread_counters[$post['tid']])) 802 { 803 $thread_counters[$post['tid']] = array( 804 'replies' => 0, 805 'unapprovedposts' => 0, 806 'deletedposts' => 0, 807 'attachmentcount' => 0 808 ); 809 } 810 if($first == 1) 811 { // all posts will be merged into this one 812 $masterpid = $post['pid']; 813 $message = $post['message']; 814 $fid = $post['fid']; 815 $mastertid = $post['tid']; 816 $first = 0; 817 $visible = $post['visible']; 818 } 819 else 820 { 821 // these are the selected posts 822 if($sep == "new_line") 823 { 824 $message .= "\n\n {$post['message']}"; 825 } 826 else 827 { 828 $message .= "[hr]{$post['message']}"; 829 } 830 831 if(!isset($forum_counters[$post['fid']])) 832 { 833 $forum_counters[$post['fid']] = array( 834 'num_posts' => 0, 835 'unapprovedposts' => 0, 836 'deletedposts' => 0 837 ); 838 } 839 840 if($post['visible'] == 1) 841 { 842 --$thread_counters[$post['tid']]['replies']; 843 $forum = get_forum($post['fid']); 844 if(!isset($user_counters[$post['uid']])) 845 { 846 $user_counters[$post['uid']] = array( 847 'num_posts' => 0, 848 'num_threads' => 0 849 ); 850 } 851 // Subtract 1 from user's post count 852 if($forum['usepostcounts'] != 0 && $post['threadvisible'] == 1) 853 { 854 // Update post count of the user of the merged posts 855 --$user_counters[$post['uid']]['num_posts']; 856 } 857 if($post['threadfirstpost'] == $post['pid'] && $forum['usethreadcounts'] != 0 && $post['threadvisible'] == 1) 858 { 859 --$user_counters[$post['uid']]['num_threads']; 860 } 861 $thread_counters[$post['tid']]['attachmentcount'] -= $post['attachmentcount']; 862 } 863 elseif($post['visible'] == 0) 864 { 865 // Subtract 1 unapproved post from post's thread 866 --$thread_counters[$post['tid']]['unapprovedposts']; 867 } 868 elseif($post['visible'] == -1) 869 { 870 // Subtract 1 deleted post from post's thread 871 --$thread_counters[$post['tid']]['deletedposts']; 872 } 873 874 // Subtract 1 post from post's forum 875 if($post['threadvisible'] == 1 && $post['visible'] == 1) 876 { 877 --$forum_counters[$post['fid']]['num_posts']; 878 } 879 elseif($post['threadvisible'] == 0 || ($post['visible'] == 0 && $post['threadvisible'] != -1)) 880 { 881 --$forum_counters[$post['fid']]['unapprovedposts']; 882 } 883 else 884 { 885 --$forum_counters[$post['fid']]['deletedposts']; 886 } 887 888 // Add attachment count to thread 889 if($visible == 1) 890 { 891 $thread_counters[$mastertid]['attachmentcount'] += $post['attachmentcount']; 892 } 893 } 894 } 895 896 // Update the message 897 $mergepost = array( 898 "message" => $db->escape_string($message), 899 ); 900 $db->update_query("posts", $mergepost, "pid = '{$masterpid}'"); 901 902 // Delete the extra posts 903 $db->delete_query("posts", "pid IN({$pidin}) AND pid != '{$masterpid}'"); 904 905 // Update pid for attachments 906 $mergepost2 = array( 907 "pid" => $masterpid, 908 ); 909 $db->update_query("attachments", $mergepost2, "pid IN({$pidin})"); 910 911 // If the first post of a thread is merged out, the first should be updated 912 $query = $db->simple_select("threads", "tid, uid, fid, visible", "firstpost IN({$pidin}) AND firstpost != '{$masterpid}'"); 913 while($thread = $db->fetch_array($query)) 914 { 915 // In some cases the first post of a thread changes 916 // Therefore resync the visible field to make sure they're the same if they're not 917 $query = $db->simple_select("posts", "pid, uid, visible", "tid='{$thread['tid']}'", array('order_by' => 'dateline, pid', 'limit' => 1)); 918 $new_firstpost = $db->fetch_array($query); 919 if($thread['visible'] != $new_firstpost['visible']) 920 { 921 $db->update_query("posts", array('visible' => $thread['visible']), "pid='{$new_firstpost['pid']}'"); 922 // Correct counters 923 if($new_firstpost['visible'] == 1) 924 { 925 --$thread_counters[$thread['tid']]['replies']; 926 } 927 elseif($new_firstpost['visible'] == -1) 928 { 929 --$thread_counters[$thread['tid']]['deletedposts']; 930 } 931 else 932 { 933 --$thread_counters[$thread['tid']]['unapprovedposts']; 934 } 935 if($thread['visible'] == 1) 936 { 937 ++$thread_counters[$thread['tid']]['replies']; 938 } 939 elseif($thread['visible'] == -1) 940 { 941 ++$thread_counters[$thread['tid']]['deletedposts']; 942 } 943 else 944 { 945 ++$thread_counters[$thread['tid']]['unapprovedposts']; 946 } 947 } 948 949 if($new_firstpost['uid'] != $thread['uid'] && $forum['usethreadcounts'] != 0 && $thread['visible'] == 1) 950 { 951 if(!isset($user_counters[$new_firstpost['uid']])) 952 { 953 $user_counters[$new_firstpost['uid']] = array( 954 'num_posts' => 0, 955 'num_threads' => 0 956 ); 957 } 958 ++$user_counters[$new_firstpost['uid']]['num_threads']; 959 } 960 update_first_post($thread['tid']); 961 } 962 963 $arguments = array("pids" => $pids, "tid" => $tid); 964 $plugins->run_hooks("class_moderation_merge_posts", $arguments); 965 966 if(!empty($thread_counters)) 967 { 968 foreach($thread_counters as $tid => $counters) 969 { 970 $counters = array( 971 'replies' => signed($counters['replies']), 972 'unapprovedposts' => signed($counters['unapprovedposts']), 973 'deletedposts' => signed($counters['deletedposts']), 974 'attachmentcount' => signed($counters['attachmentcount']) 975 ); 976 update_thread_counters($tid, $counters); 977 update_last_post($tid); 978 } 979 } 980 981 if(!empty($forum_counters)) 982 { 983 foreach($forum_counters as $fid => $counters) 984 { 985 $updated_forum_stats = array( 986 'posts' => signed($counters['num_posts']), 987 'unapprovedposts' => signed($counters['unapprovedposts']), 988 'deletedposts' => signed($counters['deletedposts']) 989 ); 990 update_forum_counters($fid, $updated_forum_stats); 991 update_forum_lastpost($fid); 992 } 993 } 994 995 if(!empty($user_counters)) 996 { 997 foreach($user_counters as $uid => $counters) 998 { 999 $update_array = array( 1000 "postnum" => "+{$counters['num_posts']}", 1001 "threadnum" => "+{$counters['num_threads']}" 1002 ); 1003 update_user_counters($uid, $update_array); 1004 } 1005 } 1006 1007 return $masterpid; 1008 } 1009 1010 /** 1011 * Move/copy thread 1012 * 1013 * @param int $tid Thread to be moved 1014 * @param int $new_fid Destination forum 1015 * @param string $method Method of movement (redirect, copy, move) 1016 * @param int $redirect_expire Expiry timestamp for redirect 1017 * @return int Thread ID 1018 */ 1019 function move_thread($tid, $new_fid, $method="redirect", $redirect_expire=0) 1020 { 1021 global $db, $plugins; 1022 1023 // Get thread info 1024 $tid = (int)$tid; 1025 $new_fid = (int)$new_fid; 1026 $redirect_expire = (int)$redirect_expire; 1027 1028 $thread = get_thread($tid, true); 1029 1030 $newforum = get_forum($new_fid); 1031 if(!$thread || !$newforum) 1032 { 1033 return false; 1034 } 1035 $fid = $thread['fid']; 1036 $forum = get_forum($fid); 1037 1038 $num_threads = $num_unapproved_threads = $num_posts = $num_unapproved_posts = $num_deleted_posts = $num_deleted_threads = 0; 1039 1040 if($thread['visible'] == 1) 1041 { 1042 $num_threads++; 1043 $num_posts = $thread['replies']+1; 1044 $num_unapproved_posts = $thread['unapprovedposts']; 1045 $num_deleted_posts = $thread['deletedposts']; 1046 } 1047 elseif($thread['visible'] == -1) 1048 { 1049 $num_deleted_threads++; 1050 // Implied forum deleted count for deleted threads 1051 $num_deleted_posts = $thread['replies']+$thread['deletedposts']+$thread['unapprovedposts']+1; 1052 } 1053 else 1054 { 1055 $num_unapproved_threads++; 1056 // Implied forum unapproved count for unapproved threads 1057 $num_unapproved_posts = $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; 1058 } 1059 1060 switch($method) 1061 { 1062 case "redirect": // move (and leave redirect) thread 1063 $arguments = array("tid" => $tid, "new_fid" => $new_fid); 1064 $plugins->run_hooks("class_moderation_move_thread_redirect", $arguments); 1065 1066 $query = $db->simple_select('threads', 'tid', "closed='moved|$tid' AND fid='$new_fid'"); 1067 while($redirect_tid = $db->fetch_field($query, 'tid')) 1068 { 1069 $this->delete_thread($redirect_tid); 1070 } 1071 $changefid = array( 1072 "fid" => $new_fid, 1073 ); 1074 $db->update_query("threads", $changefid, "tid='$tid'"); 1075 $db->update_query("posts", $changefid, "tid='$tid'"); 1076 1077 // If the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix 1078 if($thread['prefix'] != 0) 1079 { 1080 switch($db->type) 1081 { 1082 case "pgsql": 1083 case "sqlite": 1084 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 1085 break; 1086 default: 1087 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 1088 } 1089 if($db->fetch_field($query, "num_prefixes") == 0) 1090 { 1091 $sqlarray = array( 1092 "prefix" => 0, 1093 ); 1094 $db->update_query("threads", $sqlarray, "tid='$tid'"); 1095 } 1096 } 1097 1098 $threadarray = array( 1099 "fid" => $thread['fid'], 1100 "subject" => $db->escape_string($thread['subject']), 1101 "icon" => $thread['icon'], 1102 "uid" => $thread['uid'], 1103 "username" => $db->escape_string($thread['username']), 1104 "dateline" => $thread['dateline'], 1105 "lastpost" => $thread['lastpost'], 1106 "lastposteruid" => $thread['lastposteruid'], 1107 "lastposter" => $db->escape_string($thread['lastposter']), 1108 "views" => 0, 1109 "replies" => 0, 1110 "closed" => "moved|$tid", 1111 "sticky" => $thread['sticky'], 1112 "visible" => (int)$thread['visible'], 1113 "notes" => '' 1114 ); 1115 $redirect_tid = $db->insert_query("threads", $threadarray); 1116 if($redirect_expire) 1117 { 1118 $this->expire_thread($redirect_tid, $redirect_expire); 1119 } 1120 1121 // If we're moving back to a forum where we left a redirect, delete the rediect 1122 $query = $db->simple_select("threads", "tid", "closed LIKE 'moved|".(int)$tid."' AND fid='".(int)$new_fid."'"); 1123 while($redirect_tid = $db->fetch_field($query, 'tid')) 1124 { 1125 $this->delete_thread($redirect_tid); 1126 } 1127 break; 1128 case "copy":// copy thread 1129 1130 $threadarray = array( 1131 "fid" => $new_fid, 1132 "subject" => $db->escape_string($thread['subject']), 1133 "icon" => $thread['icon'], 1134 "uid" => $thread['uid'], 1135 "username" => $db->escape_string($thread['username']), 1136 "dateline" => $thread['dateline'], 1137 "firstpost" => 0, 1138 "lastpost" => $thread['lastpost'], 1139 "lastposteruid" => $thread['lastposteruid'], 1140 "lastposter" => $db->escape_string($thread['lastposter']), 1141 "views" => $thread['views'], 1142 "replies" => $thread['replies'], 1143 "closed" => $thread['closed'], 1144 "sticky" => $thread['sticky'], 1145 "visible" => (int)$thread['visible'], 1146 "unapprovedposts" => $thread['unapprovedposts'], 1147 "deletedposts" => $thread['deletedposts'], 1148 "attachmentcount" => $thread['attachmentcount'], 1149 "prefix" => $thread['prefix'], 1150 "notes" => '' 1151 ); 1152 1153 $arguments = array("tid" => $tid, "new_fid" => $new_fid); 1154 $plugins->run_hooks("class_moderation_copy_thread", $arguments); 1155 1156 // If the thread has a prefix and the destination forum doesn't accept that prefix, don't copy the prefix 1157 if($threadarray['prefix'] != 0) 1158 { 1159 switch($db->type) 1160 { 1161 case "pgsql": 1162 case "sqlite": 1163 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 1164 break; 1165 default: 1166 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 1167 } 1168 if($db->fetch_field($query, "num_prefixes") == 0) 1169 { 1170 $threadarray['prefix'] = 0; 1171 } 1172 } 1173 1174 $newtid = $db->insert_query("threads", $threadarray); 1175 1176 if($thread['poll'] != 0) 1177 { 1178 $query = $db->simple_select("polls", "*", "tid = '{$thread['tid']}'"); 1179 $poll = $db->fetch_array($query); 1180 1181 $poll_array = array( 1182 'tid' => $newtid, 1183 'question' => $db->escape_string($poll['question']), 1184 'dateline' => $poll['dateline'], 1185 'options' => $db->escape_string($poll['options']), 1186 'votes' => $db->escape_string($poll['votes']), 1187 'numoptions' => $poll['numoptions'], 1188 'numvotes' => $poll['numvotes'], 1189 'timeout' => $poll['timeout'], 1190 'closed' => $poll['closed'], 1191 'multiple' => $poll['multiple'], 1192 'public' => $poll['public'] 1193 ); 1194 $new_pid = $db->insert_query("polls", $poll_array); 1195 1196 $query = $db->simple_select("pollvotes", "*", "pid = '{$poll['pid']}'"); 1197 while($pollvote = $db->fetch_array($query)) 1198 { 1199 $pollvote_array = array( 1200 'pid' => $new_pid, 1201 'uid' => $pollvote['uid'], 1202 'voteoption' => $pollvote['voteoption'], 1203 'dateline' => $pollvote['dateline'], 1204 ); 1205 $db->insert_query("pollvotes", $pollvote_array); 1206 } 1207 1208 $db->update_query("threads", array('poll' => $new_pid), "tid='{$newtid}'"); 1209 } 1210 1211 $query = $db->simple_select("posts", "*", "tid = '{$thread['tid']}'"); 1212 while($post = $db->fetch_array($query)) 1213 { 1214 $post_array = array( 1215 'tid' => $newtid, 1216 'fid' => $new_fid, 1217 'subject' => $db->escape_string($post['subject']), 1218 'icon' => $post['icon'], 1219 'uid' => $post['uid'], 1220 'username' => $db->escape_string($post['username']), 1221 'dateline' => $post['dateline'], 1222 'ipaddress' => $db->escape_binary($post['ipaddress']), 1223 'includesig' => $post['includesig'], 1224 'smilieoff' => $post['smilieoff'], 1225 'edituid' => $post['edituid'], 1226 'edittime' => $post['edittime'], 1227 'visible' => $post['visible'], 1228 'message' => $db->escape_string($post['message']), 1229 ); 1230 $pid = $db->insert_query("posts", $post_array); 1231 1232 // Properly set our new firstpost in our new thread 1233 if($thread['firstpost'] == $post['pid']) 1234 { 1235 $db->update_query("threads", array('firstpost' => $pid), "tid='{$newtid}'"); 1236 } 1237 1238 // Insert attachments for this post 1239 $query2 = $db->simple_select("attachments", "*", "pid = '{$post['pid']}'"); 1240 while($attachment = $db->fetch_array($query2)) 1241 { 1242 $attachment_array = array( 1243 'pid' => $pid, 1244 'uid' => $attachment['uid'], 1245 'filename' => $db->escape_string($attachment['filename']), 1246 'filetype' => $db->escape_string($attachment['filetype']), 1247 'filesize' => $attachment['filesize'], 1248 'attachname' => $db->escape_string($attachment['attachname']), 1249 'downloads' => $attachment['downloads'], 1250 'visible' => $attachment['visible'], 1251 'thumbnail' => $db->escape_string($attachment['thumbnail']) 1252 ); 1253 $new_aid = $db->insert_query("attachments", $attachment_array); 1254 1255 $post['message'] = str_replace("[attachment={$attachment['aid']}]", "[attachment={$new_aid}]", $post['message']); 1256 } 1257 1258 if(strpos($post['message'], "[attachment=") !== false) 1259 { 1260 $db->update_query("posts", array('message' => $db->escape_string($post['message'])), "pid='{$pid}'"); 1261 } 1262 } 1263 1264 update_thread_data($newtid); 1265 1266 $the_thread = $newtid; 1267 break; 1268 default: 1269 case "move": // plain move thread 1270 $arguments = array("tid" => $tid, "new_fid" => $new_fid); 1271 $plugins->run_hooks("class_moderation_move_simple", $arguments); 1272 1273 $sqlarray = array( 1274 "fid" => $new_fid, 1275 ); 1276 $db->update_query("threads", $sqlarray, "tid='$tid'"); 1277 $db->update_query("posts", $sqlarray, "tid='$tid'"); 1278 1279 // If the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix 1280 if($thread['prefix'] != 0) 1281 { 1282 switch($db->type) 1283 { 1284 case "pgsql": 1285 case "sqlite": 1286 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 1287 break; 1288 default: 1289 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 1290 } 1291 if($db->fetch_field($query, "num_prefixes") == 0) 1292 { 1293 $sqlarray = array( 1294 "prefix" => 0, 1295 ); 1296 $db->update_query("threads", $sqlarray, "tid='$tid'"); 1297 } 1298 } 1299 1300 // If we're moving back to a forum where we left a redirect, delete the rediect 1301 $query = $db->simple_select("threads", "tid", "closed LIKE 'moved|".(int)$tid."' AND fid='".(int)$new_fid."'"); 1302 while($redirect_tid = $db->fetch_field($query, 'tid')) 1303 { 1304 $this->delete_thread($redirect_tid); 1305 } 1306 break; 1307 } 1308 1309 // Do post and thread count changes if changing between countable and non-countable forums 1310 $query = $db->query(" 1311 SELECT COUNT(p.pid) AS posts, u.uid 1312 FROM ".TABLE_PREFIX."posts p 1313 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 1314 WHERE p.tid='$tid' AND p.visible=1 1315 GROUP BY u.uid 1316 ORDER BY posts DESC 1317 "); 1318 while($posters = $db->fetch_array($query)) 1319 { 1320 $pcount = 0; 1321 if($forum['usepostcounts'] == 1 && $method != 'copy' && $newforum['usepostcounts'] == 0 && $thread['visible'] == 1) 1322 { 1323 $pcount -= $posters['posts']; 1324 } 1325 if(($forum['usepostcounts'] == 0 || $method == 'copy') && $newforum['usepostcounts'] == 1 && $thread['visible'] == 1) 1326 { 1327 $pcount += $posters['posts']; 1328 } 1329 1330 if($pcount > 0) 1331 { 1332 update_user_counters($posters['uid'], array('postnum' => "+$pcount")); 1333 } 1334 elseif($pcount < 0) 1335 { 1336 update_user_counters($posters['uid'], array('postnum' => $pcount)); 1337 } 1338 } 1339 1340 if($forum['usethreadcounts'] == 1 && $method != 'copy' && $newforum['usethreadcounts'] == 0 && $thread['visible'] == 1) 1341 { 1342 update_user_counters($thread['uid'], array('threadnum' => "-1")); 1343 } 1344 elseif(($forum['usethreadcounts'] == 0 || $method == 'copy') && $newforum['usethreadcounts'] == 1 && $thread['visible'] == 1) 1345 { 1346 update_user_counters($thread['uid'], array('threadnum' => "+1")); 1347 } 1348 1349 // Update forum counts 1350 $update_array = array( 1351 "threads" => "+{$num_threads}", 1352 "unapprovedthreads" => "+{$num_unapproved_threads}", 1353 "posts" => "+{$num_posts}", 1354 "unapprovedposts" => "+{$num_unapproved_posts}", 1355 "deletedthreads" => "+{$num_deleted_threads}", 1356 "deletedposts" => "+{$num_deleted_posts}" 1357 ); 1358 update_forum_counters($new_fid, $update_array); 1359 update_forum_lastpost($new_fid); 1360 1361 if($method != "copy") 1362 { 1363 // The redirect needs to be counted, too 1364 if($method == "redirect") 1365 { 1366 if($thread['visible'] == -1) 1367 { 1368 --$num_deleted_threads; 1369 --$num_deleted_posts; 1370 } 1371 elseif($thread['visible'] == 0) 1372 { 1373 --$num_unapproved_threads; 1374 --$num_unapproved_posts; 1375 } 1376 else 1377 { 1378 --$num_threads; 1379 --$num_posts; 1380 } 1381 } 1382 $update_array = array( 1383 "threads" => "-{$num_threads}", 1384 "unapprovedthreads" => "-{$num_unapproved_threads}", 1385 "posts" => "-{$num_posts}", 1386 "unapprovedposts" => "-{$num_unapproved_posts}", 1387 "deletedthreads" => "-{$num_deleted_threads}", 1388 "deletedposts" => "-{$num_deleted_posts}" 1389 ); 1390 update_forum_counters($fid, $update_array); 1391 update_forum_lastpost($fid); 1392 } 1393 1394 if(isset($newtid)) 1395 { 1396 return $newtid; 1397 } 1398 else 1399 { 1400 // Remove thread subscriptions for the users who no longer have permission to view the thread 1401 $this->remove_thread_subscriptions($tid, false, $new_fid); 1402 1403 return $tid; 1404 } 1405 } 1406 1407 /** 1408 * Merge one thread into another 1409 * 1410 * @param int $mergetid Thread that will be merged into destination 1411 * @param int $tid Destination thread 1412 * @param string $subject New thread subject 1413 * @return boolean 1414 */ 1415 function merge_threads($mergetid, $tid, $subject) 1416 { 1417 global $db, $mybb, $mergethread, $thread, $plugins, $cache; 1418 1419 $mergetid = (int)$mergetid; 1420 $tid = (int)$tid; 1421 1422 if(!isset($mergethread['tid']) || $mergethread['tid'] != $mergetid) 1423 { 1424 $mergethread = get_thread($mergetid); 1425 } 1426 if(!isset($thread['tid']) || $thread['tid'] != $tid) 1427 { 1428 $thread = get_thread($tid); 1429 } 1430 1431 if(!$mergethread || !$thread) 1432 { 1433 return false; 1434 } 1435 1436 $forum_cache = $cache->read('forums'); 1437 1438 $threadarray = array(); 1439 if(!$thread['poll'] && $mergethread['poll']) 1440 { 1441 $threadarray['poll'] = $mergethread['poll']; 1442 $sqlarray = array( 1443 "tid" => $tid, 1444 ); 1445 $db->update_query("polls", $sqlarray, "tid='".(int)$mergethread['tid']."'"); 1446 } 1447 // Both the old and the new thread have polls? Remove one 1448 elseif($mergethread['poll']) 1449 { 1450 $db->delete_query("polls", "pid='{$mergethread['poll']}'"); 1451 $db->delete_query("pollvotes", "pid='{$mergethread['poll']}'"); 1452 } 1453 1454 $subject = $db->escape_string($subject); 1455 $threadarray['subject'] = $subject; 1456 1457 $user_posts = array(); 1458 if($thread['visible'] != $mergethread['visible'] || $forum_cache[$thread['fid']]['usepostcounts'] != $forum_cache[$mergethread['fid']]['usepostcounts']) 1459 { 1460 $query = $db->query(" 1461 SELECT uid, COUNT(pid) AS postnum 1462 FROM ".TABLE_PREFIX."posts 1463 WHERE tid='{$mergetid}' AND visible=1 1464 GROUP BY uid 1465 "); 1466 while($post = $db->fetch_array($query)) 1467 { 1468 // Update user counters 1469 if($mergethread['visible'] == 1 && $forum_cache[$mergethread['fid']]['usepostcounts'] == 1) 1470 { 1471 $user_posts[$post['uid']]['postnum'] -= $post['postnum']; 1472 } 1473 elseif($thread['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1) 1474 { 1475 $user_posts[$post['uid']]['postnum'] += $post['postnum']; 1476 } 1477 } 1478 } 1479 1480 $sqlarray = array( 1481 "tid" => $tid, 1482 "fid" => $thread['fid'], 1483 "replyto" => 0, 1484 ); 1485 $db->update_query("posts", $sqlarray, "tid='{$mergetid}'"); 1486 1487 $sqlarray = array( 1488 "closed" => "moved|{$tid}", 1489 ); 1490 $db->update_query("threads", $sqlarray, "closed='moved|{$mergetid}'"); 1491 $sqlarray = array( 1492 "tid" => $tid, 1493 ); 1494 1495 // Update the thread ratings 1496 $new_numrating = $thread['numratings'] + $mergethread['numratings']; 1497 $new_threadrating = $thread['totalratings'] + $mergethread['totalratings']; 1498 1499 $threadarray["numratings"] = $new_numrating; 1500 $threadarray["totalratings"] = $new_threadrating; 1501 $db->update_query("threads", $threadarray, "tid = '{$tid}'"); 1502 1503 // Check if we have a thread subscription already for our new thread 1504 $subscriptions = array(); 1505 1506 $query = $db->simple_select("threadsubscriptions", "tid, uid", "tid='{$mergetid}' OR tid='{$tid}'"); 1507 while($subscription = $db->fetch_array($query)) 1508 { 1509 if(!isset($subscriptions[$subscription['tid']])) 1510 { 1511 $subscriptions[$subscription['tid']] = array(); 1512 } 1513 $subscriptions[$subscription['tid']][] = $subscription['uid']; 1514 } 1515 1516 // Update any subscriptions for the merged thread 1517 if(!empty($subscriptions[$mergetid])) 1518 { 1519 $update_users = array(); 1520 foreach($subscriptions[$mergetid] as $user) 1521 { 1522 if(!isset($subscriptions[$tid]) || !in_array($user, $subscriptions[$tid])) 1523 { 1524 // User doesn't have a $tid subscription 1525 $update_users[] = $user; 1526 } 1527 } 1528 1529 if(!empty($update_users)) 1530 { 1531 $update_array = array( 1532 "tid" => $tid 1533 ); 1534 1535 $update_users = implode(",", $update_users); 1536 $db->update_query("threadsubscriptions", $update_array, "tid = '{$mergetid}' AND uid IN ({$update_users})"); 1537 } 1538 } 1539 1540 // Remove source thread subscriptions 1541 $db->delete_query("threadsubscriptions", "tid = '{$mergetid}'"); 1542 1543 $arguments = array("mergetid" => $mergetid, "tid" => $tid, "subject" => $subject); 1544 $plugins->run_hooks("class_moderation_merge_threads", $arguments); 1545 1546 $this->delete_thread($mergetid); 1547 1548 // Add the former first post 1549 if($mergethread['visible'] == 1) 1550 { 1551 ++$mergethread['replies']; 1552 } 1553 elseif($mergethread['visible'] == -1) 1554 { 1555 ++$mergethread['deletedposts']; 1556 } 1557 else 1558 { 1559 ++$mergethread['unapprovedposts']; 1560 } 1561 1562 // In some cases the thread we may be merging with may cause us to have a new firstpost if it is an older thread 1563 // Therefore resync the visible field to make sure they're the same if they're not 1564 $query = $db->simple_select("posts", "pid, uid, visible", "tid='{$tid}'", array('order_by' => 'dateline, pid', 'limit' => 1)); 1565 $new_firstpost = $db->fetch_array($query); 1566 if($thread['visible'] != $new_firstpost['visible']) 1567 { 1568 $db->update_query("posts", array('visible' => $thread['visible']), "pid='{$new_firstpost['pid']}'"); 1569 if($new_firstpost['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1) 1570 { 1571 --$user_posts[$post['uid']]['postnum']; 1572 } 1573 elseif($thread['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1) 1574 { 1575 ++$user_posts[$post['uid']]['postnum']; 1576 } 1577 } 1578 // Update first post if needed 1579 if($new_firstpost['pid'] != $thread['firstpost']) 1580 { 1581 update_first_post($thread['tid']); 1582 } 1583 1584 // Update thread count if thread has a new firstpost and is visible 1585 if($thread['uid'] != $new_firstpost['uid'] && $thread['visible'] == 1 && $forum_cache[$thread['fid']]['usethreadcounts'] == 1) 1586 { 1587 if(!isset($user_posts[$thread['uid']]['threadnum'])) 1588 { 1589 $user_posts[$thread['uid']]['threadnum'] = 0; 1590 } 1591 --$user_posts[$thread['uid']]['threadnum']; 1592 if(!isset($user_posts[$new_firstpost['uid']]['threadnum'])) 1593 { 1594 $user_posts[$new_firstpost['uid']]['threadnum'] = 0; 1595 } 1596 ++$user_posts[$new_firstpost['uid']]['threadnum']; 1597 } 1598 1599 // Thread is not in current forum 1600 if($mergethread['fid'] != $thread['fid']) 1601 { 1602 // If new thread is unapproved, implied counter comes in to effect 1603 if($thread['visible'] == 0) 1604 { 1605 $updated_stats = array( 1606 "unapprovedposts" => '+'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts']) 1607 ); 1608 } 1609 elseif($thread['visible'] == -1) 1610 { 1611 $updated_stats = array( 1612 "deletedposts" => '+'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts']) 1613 ); 1614 } 1615 else 1616 { 1617 $updated_stats = array( 1618 "posts" => "+{$mergethread['replies']}", 1619 "unapprovedposts" => "+{$mergethread['unapprovedposts']}", 1620 "deletedposts" => "+{$mergethread['deletedposts']}" 1621 ); 1622 } 1623 update_forum_counters($thread['fid'], $updated_stats); 1624 1625 // If old thread is unapproved, implied counter comes in to effect 1626 if($mergethread['visible'] == 0) 1627 { 1628 $updated_stats = array( 1629 "unapprovedposts" => '-'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts']) 1630 ); 1631 } 1632 elseif($mergethread['visible'] == -1) 1633 { 1634 $updated_stats = array( 1635 "deletedposts" => '-'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts']) 1636 ); 1637 } 1638 else 1639 { 1640 $updated_stats = array( 1641 "posts" => "-{$mergethread['replies']}", 1642 "unapprovedposts" => "-{$mergethread['unapprovedposts']}", 1643 "deletedposts" => "-{$mergethread['deletedposts']}" 1644 ); 1645 } 1646 update_forum_counters($mergethread['fid'], $updated_stats); 1647 update_forum_lastpost($mergethread['fid']); 1648 } 1649 // Visibility changed 1650 elseif($mergethread['visible'] != $thread['visible']) 1651 { 1652 $updated_stats = array( 1653 'posts' => 0, 1654 'unapprovedposts' => 0, 1655 'deletedposts' => 0 1656 ); 1657 1658 // If old thread is unapproved, implied counter comes in to effect 1659 if($mergethread['visible'] == 0) 1660 { 1661 $updated_stats['unapprovedposts'] -= $mergethread['replies']+$mergethread['deletedposts']; 1662 $updated_stats['posts'] += $mergethread['replies']; 1663 $updated_stats['deletedposts'] += $mergethread['deletedposts']; 1664 } 1665 elseif($mergethread['visible'] == -1) 1666 { 1667 $updated_stats['deletedposts'] -= $mergethread['replies']+$mergethread['unapprovedposts']; 1668 $updated_stats['posts'] += $mergethread['replies']; 1669 $updated_stats['unapprovedposts'] += $mergethread['unapprovedposts']; 1670 } 1671 1672 // If new thread is unapproved, implied counter comes in to effect 1673 if($thread['visible'] == 0) 1674 { 1675 $updated_stats['unapprovedposts'] += $mergethread['replies']+$mergethread['deletedposts']; 1676 $updated_stats['posts'] -= $mergethread['replies']; 1677 $updated_stats['deletedposts'] -= $mergethread['deletedposts']; 1678 } 1679 elseif($thread['visible'] == -1) 1680 { 1681 $updated_stats['deletedposts'] += $mergethread['replies']+$mergethread['unapprovedposts']; 1682 $updated_stats['posts'] -= $mergethread['replies']; 1683 $updated_stats['unapprovedposts'] -= $mergethread['unapprovedposts']; 1684 } 1685 1686 $new_stats = array(); 1687 if($updated_stats['posts'] < 0) 1688 { 1689 $new_stats['posts'] = $updated_stats['posts']; 1690 } 1691 elseif($updated_stats['posts'] > 0) 1692 { 1693 $new_stats['posts'] = "+{$updated_stats['posts']}"; 1694 } 1695 1696 if($updated_stats['unapprovedposts'] < 0) 1697 { 1698 $new_stats['unapprovedposts'] = $updated_stats['unapprovedposts']; 1699 } 1700 elseif($updated_stats['unapprovedposts'] > 0) 1701 { 1702 $new_stats['unapprovedposts'] = "+{$updated_stats['unapprovedposts']}"; 1703 } 1704 1705 if($updated_stats['deletedposts'] < 0) 1706 { 1707 $new_stats['deletedposts'] = $updated_stats['deletedposts']; 1708 } 1709 elseif($updated_stats['deletedposts'] > 0) 1710 { 1711 $new_stats['deletedposts'] = "+{$updated_stats['deletedposts']}"; 1712 } 1713 1714 if(!empty($new_stats)) 1715 { 1716 update_forum_counters($mergethread['fid'], $new_stats); 1717 update_forum_lastpost($mergethread['fid']); 1718 } 1719 } 1720 1721 if($thread['visible'] != $new_firstpost['visible']) 1722 { 1723 // Correct counters 1724 if($new_firstpost['visible'] == 1) 1725 { 1726 --$mergethread['replies']; 1727 } 1728 elseif($new_firstpost['visible'] == -1) 1729 { 1730 --$mergethread['deletedposts']; 1731 } 1732 else 1733 { 1734 --$mergethread['unapprovedposts']; 1735 } 1736 if($thread['visible'] == 1) 1737 { 1738 ++$mergethread['replies']; 1739 } 1740 elseif($thread['visible'] == -1) 1741 { 1742 ++$mergethread['deletedposts']; 1743 } 1744 else 1745 { 1746 ++$mergethread['unapprovedposts']; 1747 } 1748 } 1749 1750 // Update user counters 1751 foreach($user_posts as $uid => $counters) 1752 { 1753 $update_array = array( 1754 "postnum" => "+{$counters['postnum']}", 1755 "threadnum" => "+{$counters['threadnum']}", 1756 ); 1757 update_user_counters($uid, $update_array); 1758 } 1759 1760 $updated_stats = array( 1761 "replies" => "+{$mergethread['replies']}", 1762 "attachmentcount" => "+{$mergethread['attachmentcount']}", 1763 "unapprovedposts" => "+{$mergethread['unapprovedposts']}", 1764 "deletedposts" => "+{$mergethread['deletedposts']}" 1765 ); 1766 update_thread_counters($tid, $updated_stats); 1767 update_last_post($tid); 1768 1769 // Forum last post has to be updated after thread 1770 update_forum_lastpost($thread['fid']); 1771 return true; 1772 } 1773 1774 /** 1775 * Split posts into a new/existing thread 1776 * 1777 * @param array $pids PIDs of posts to split 1778 * @param int $tid Original thread ID (this is only used as a base for the new 1779 * thread; it can be set to 0 when the posts specified are coming from more 1780 * than 1 thread) 1781 * @param int $moveto Destination forum 1782 * @param string $newsubject New thread subject 1783 * @param int $destination_tid TID if moving into existing thread 1784 * @return int|bool New thread ID or false on failure 1785 */ 1786 function split_posts($pids, $tid, $moveto, $newsubject, $destination_tid=0) 1787 { 1788 global $db, $thread, $plugins, $cache; 1789 1790 $tid = (int)$tid; 1791 $moveto = (int)$moveto; 1792 $newtid = (int)$destination_tid; 1793 1794 // Make sure we only have valid values 1795 $pids = array_map('intval', $pids); 1796 1797 $pids_list = implode(',', $pids); 1798 1799 // Get forum infos 1800 $forum_cache = $cache->read('forums'); 1801 1802 if(empty($pids) || !$forum_cache[$moveto]) 1803 { 1804 return false; 1805 } 1806 1807 // Get the first split post 1808 $query = $db->simple_select('posts', 'pid,uid,visible,icon,username,dateline', 'pid IN ('.$pids_list.')', array('order_by' => 'dateline, pid', 'limit' => 1)); 1809 1810 $post_info = $db->fetch_array($query); 1811 1812 $visible = $post_info['visible']; 1813 1814 $forum_counters[$moveto] = array( 1815 'threads' => 0, 1816 'deletedthreads' => 0, 1817 'unapprovedthreads' => 0, 1818 'posts' => 0, 1819 'unapprovedposts' => 0, 1820 'deletedposts' => 0 1821 ); 1822 1823 $user_counters = array(); 1824 1825 if($destination_tid == 0) 1826 { 1827 // Splitting into a new thread 1828 // Create the new thread 1829 $newsubject = $db->escape_string($newsubject); 1830 $newthread = array( 1831 "fid" => $moveto, 1832 "subject" => $newsubject, 1833 "icon" => (int)$post_info['icon'], 1834 "uid" => (int)$post_info['uid'], 1835 "username" => $db->escape_string($post_info['username']), 1836 "dateline" => (int)$post_info['dateline'], 1837 "firstpost" => $post_info['pid'], 1838 "lastpost" => 0, 1839 "lastposter" => '', 1840 "visible" => (int)$visible, 1841 "notes" => '' 1842 ); 1843 $newtid = $db->insert_query("threads", $newthread); 1844 1845 if($visible == 1) 1846 { 1847 ++$forum_counters[$moveto]['threads']; 1848 if(!isset($user_counters[$newthread['uid']])) 1849 { 1850 $user_counters[$newthread['uid']] = array( 1851 'postnum' => 0, 1852 'threadnum' => 0 1853 ); 1854 } 1855 ++$user_counters[$newthread['uid']]['threadnum']; 1856 } 1857 elseif($visible == -1) 1858 { 1859 ++$forum_counters[$moveto]['deletedthreads']; 1860 } 1861 else 1862 { 1863 // Unapproved thread? 1864 ++$forum_counters[$moveto]['unapprovedthreads']; 1865 } 1866 } 1867 else 1868 { 1869 $newthread = get_thread($newtid); 1870 if(!$newthread) 1871 { 1872 return false; 1873 } 1874 $moveto = $newthread['fid']; 1875 } 1876 1877 // Get selected posts before moving forums to keep old fid 1878 $original_posts_query = $db->query(" 1879 SELECT p.pid, p.tid, p.fid, p.visible, p.uid, p.dateline, t.visible as threadvisible, t.firstpost, COUNT(a.aid) as postattachmentcount 1880 FROM ".TABLE_PREFIX."posts p 1881 LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid) 1882 LEFT JOIN ".TABLE_PREFIX."attachments a ON (a.pid=p.pid AND a.visible=1) 1883 WHERE p.pid IN ($pids_list) 1884 GROUP BY p.pid 1885 "); 1886 1887 // Move the selected posts over 1888 $sqlarray = array( 1889 "tid" => $newtid, 1890 "fid" => $moveto, 1891 "replyto" => 0 1892 ); 1893 $db->update_query("posts", $sqlarray, "pid IN ($pids_list)"); 1894 1895 $thread_counters[$newtid] = array( 1896 'replies' => 0, 1897 'unapprovedposts' => 0, 1898 'deletedposts' => 0, 1899 'attachmentcount' => 0 1900 ); 1901 1902 // Get posts being merged 1903 while($post = $db->fetch_array($original_posts_query)) 1904 { 1905 if(!isset($thread_counters[$post['tid']])) 1906 { 1907 $thread_counters[$post['tid']] = array( 1908 'replies' => 0, 1909 'unapprovedposts' => 0, 1910 'deletedposts' => 0, 1911 'attachmentcount' => 0 1912 ); 1913 } 1914 if(!isset($forum_counters[$post['fid']])) 1915 { 1916 $forum_counters[$post['fid']] = array( 1917 'posts' => 0, 1918 'unapprovedposts' => 0, 1919 'deletedposts' => 0 1920 ); 1921 } 1922 if(!isset($user_counters[$post['uid']])) 1923 { 1924 $user_counters[$post['uid']] = array( 1925 'postnum' => 0, 1926 'threadnum' => 0 1927 ); 1928 } 1929 if($post['visible'] == 1) 1930 { 1931 // Modify users' post counts 1932 if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1 && ($forum_cache[$moveto]['usepostcounts'] == 0 || $newthread['visible'] != 1)) 1933 { 1934 // Moving into a forum that doesn't count post counts 1935 --$user_counters[$post['uid']]['postnum']; 1936 } 1937 1938 // Subtract 1 from the old thread's replies 1939 --$thread_counters[$post['tid']]['replies']; 1940 } 1941 elseif($post['visible'] == 0) 1942 { 1943 // Unapproved post 1944 // Subtract 1 from the old thread's unapproved posts 1945 --$thread_counters[$post['tid']]['unapprovedposts']; 1946 } 1947 elseif($post['visible'] == -1) 1948 { 1949 // Soft deleted post 1950 // Subtract 1 from the old thread's deleted posts 1951 --$thread_counters[$post['tid']]['deletedposts']; 1952 } 1953 1954 // Subtract 1 from the old forum's posts 1955 if($post['threadvisible'] == 1 && $post['visible'] == 1) 1956 { 1957 --$forum_counters[$post['fid']]['posts']; 1958 } 1959 elseif($post['threadvisible'] == 0 || ($post['visible'] == 0 && $post['threadvisible'] == 1)) 1960 { 1961 --$forum_counters[$post['fid']]['unapprovedposts']; 1962 } 1963 else 1964 { 1965 --$forum_counters[$post['fid']]['deletedposts']; 1966 } 1967 1968 // Subtract attachment counts from old thread and add to new thread (which are counted regardless of post or attachment unapproval at time of coding) 1969 $thread_counters[$post['tid']]['attachmentcount'] -= $post['postattachmentcount']; 1970 $thread_counters[$newtid]['attachmentcount'] += $post['postattachmentcount']; 1971 1972 if($post['firstpost'] == $post['pid']) 1973 { 1974 // In some cases the first post of a thread changes 1975 // Therefore resync the visible field to make sure they're the same if they're not 1976 $query = $db->simple_select("posts", "pid, visible, uid", "tid='{$post['tid']}'", array('order_by' => 'dateline, pid', 'limit' => 1)); 1977 $new_firstpost = $db->fetch_array($query); 1978 1979 if(!isset($user_counters[$new_firstpost['uid']])) 1980 { 1981 $user_counters[$new_firstpost['uid']] = array( 1982 'postnum' => 0, 1983 'threadnum' => 0 1984 ); 1985 } 1986 1987 // Update post counters if visibility changes 1988 if($post['threadvisible'] != $new_firstpost['visible']) 1989 { 1990 $db->update_query("posts", array('visible' => $post['threadvisible']), "pid='{$new_firstpost['pid']}'"); 1991 // Subtract new first post 1992 if($new_firstpost['visible'] == 1) 1993 { 1994 --$thread_counters[$post['tid']]['replies']; 1995 if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1) 1996 { 1997 --$user_counters[$new_firstpost['uid']]['postnum']; 1998 } 1999 } 2000 elseif($new_firstpost['visible'] == -1) 2001 { 2002 --$thread_counters[$post['tid']]['deletedposts']; 2003 } 2004 else 2005 { 2006 --$thread_counters[$post['tid']]['unapprovedposts']; 2007 } 2008 if($post['threadvisible'] == 0 || ($new_firstpost['visible'] == 0 && $post['threadvisible'] == 1)) 2009 { 2010 --$forum_counters[$post['fid']]['unapprovedposts']; 2011 } 2012 else 2013 { 2014 --$forum_counters[$post['fid']]['deletedposts']; 2015 } 2016 2017 // Add old first post 2018 if($post['threadvisible'] == 1) 2019 { 2020 ++$thread_counters[$post['tid']]['replies']; 2021 ++$forum_counters[$post['fid']]['posts']; 2022 if($forum_cache[$post['fid']]['usepostcounts'] == 1) 2023 { 2024 ++$user_counters[$new_firstpost['uid']]['postnum']; 2025 } 2026 } 2027 elseif($post['threadvisible'] == -1) 2028 { 2029 ++$thread_counters[$post['tid']]['deletedposts']; 2030 ++$forum_counters[$post['fid']]['deletedposts']; 2031 } 2032 else 2033 { 2034 ++$thread_counters[$post['tid']]['unapprovedposts']; 2035 ++$forum_counters[$post['fid']]['unapprovedposts']; 2036 } 2037 } 2038 2039 // Update user thread counter if thread opener changes 2040 if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usethreadcounts'] == 1 && $post['uid'] != $new_firstpost['uid']) 2041 { 2042 // Subtract thread from old thread opener 2043 --$user_counters[$post['uid']]['threadnum']; 2044 // Add thread to new thread opener 2045 ++$user_counters[$new_firstpost['uid']]['threadnum']; 2046 } 2047 update_first_post($post['tid']); 2048 } 2049 2050 // This is the new first post of an existing thread? 2051 if($post['pid'] == $post_info['pid'] && $post['dateline'] < $newthread['dateline']) 2052 { 2053 // Update post counters if visibility changes 2054 if($post['visible'] != $newthread['visible']) 2055 { 2056 $db->update_query("posts", array('visible' => $newthread['visible']), "pid='{$post['pid']}'"); 2057 2058 // This is needed to update the forum counters correctly 2059 $post['visible'] = $newthread['visible']; 2060 } 2061 2062 // Update user thread counter if thread opener changes 2063 if($newthread['visible'] == 1 && $forum_cache[$newthread['fid']]['usethreadcounts'] == 1 && $post['uid'] != $newthread['uid']) 2064 { 2065 // Add thread to new thread opener 2066 ++$user_counters[$post['uid']]['threadnum']; 2067 if(!isset($user_counters[$newthread['uid']])) 2068 { 2069 $user_counters[$newthread['uid']] = array( 2070 'postnum' => 0, 2071 'threadnum' => 0 2072 ); 2073 } 2074 // Subtract thread from old thread opener 2075 --$user_counters[$newthread['uid']]['threadnum']; 2076 } 2077 update_first_post($newtid); 2078 } 2079 2080 if($post['visible'] == 1) 2081 { 2082 // Modify users' post counts 2083 if($newthread['visible'] == 1 && ($forum_cache[$post['fid']]['usepostcounts'] == 0 || $post['threadvisible'] != 1) && $forum_cache[$moveto]['usepostcounts'] == 1) 2084 { 2085 // Moving into a forum that does count post counts 2086 ++$user_counters[$post['uid']]['postnum']; 2087 } 2088 2089 // Add 1 to the new thread's replies 2090 ++$thread_counters[$newtid]['replies']; 2091 } 2092 elseif($post['visible'] == 0) 2093 { 2094 // Unapproved post 2095 // Add 1 to the new thread's unapproved posts 2096 ++$thread_counters[$newtid]['unapprovedposts']; 2097 } 2098 elseif($post['visible'] == -1) 2099 { 2100 // Soft deleted post 2101 // Add 1 to the new thread's deleted posts 2102 ++$thread_counters[$newtid]['deletedposts']; 2103 } 2104 2105 // Add 1 to the new forum's posts 2106 if($newthread['visible'] == 1 && $post['visible'] == 1) 2107 { 2108 ++$forum_counters[$moveto]['posts']; 2109 } 2110 elseif($newthread['visible'] == 0 || ($post['visible'] == 0 && $newthread['visible'] == 1)) 2111 { 2112 ++$forum_counters[$moveto]['unapprovedposts']; 2113 } 2114 else 2115 { 2116 ++$forum_counters[$moveto]['deletedposts']; 2117 } 2118 } 2119 2120 if($destination_tid == 0 && $newthread['visible'] == 1) 2121 { 2122 // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post 2123 --$thread_counters[$newtid]['replies']; 2124 } 2125 elseif($destination_tid == 0 && $newthread['visible'] == 0) 2126 { 2127 // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post 2128 --$thread_counters[$newtid]['unapprovedposts']; 2129 } 2130 elseif($destination_tid == 0 && $newthread['visible'] == -1) 2131 { 2132 // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post 2133 --$thread_counters[$newtid]['deletedposts']; 2134 } 2135 2136 $arguments = array("pids" => $pids, "tid" => $tid, "moveto" => $moveto, "newsubject" => $newsubject, "destination_tid" => $destination_tid); 2137 $plugins->run_hooks("class_moderation_split_posts", $arguments); 2138 2139 // Update user post counts 2140 if(!empty($user_counters)) 2141 { 2142 foreach($user_counters as $uid => $counters) 2143 { 2144 foreach($counters as $key => $counter) 2145 { 2146 if($counter >= 0) 2147 { 2148 $counters[$key] = "+{$counter}"; // add the addition operator for query 2149 } 2150 } 2151 update_user_counters($uid, $counters); 2152 } 2153 } 2154 2155 // Update thread counters 2156 if(is_array($thread_counters)) 2157 { 2158 foreach($thread_counters as $tid => $counters) 2159 { 2160 if($tid == $newtid) 2161 { 2162 // Update the subject of the first post in the new thread 2163 $query = $db->simple_select("posts", "pid", "tid='$newtid'", array('order_by' => 'dateline, pid', 'limit' => 1)); 2164 $newthread = $db->fetch_array($query); 2165 $sqlarray = array( 2166 "subject" => $newsubject, 2167 "replyto" => 0 2168 ); 2169 $db->update_query("posts", $sqlarray, "pid='{$newthread['pid']}'"); 2170 } 2171 else 2172 { 2173 // Update the subject of the first post in the old thread 2174 $query = $db->query(" 2175 SELECT p.pid, t.subject 2176 FROM ".TABLE_PREFIX."posts p 2177 LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid) 2178 WHERE p.tid='{$tid}' 2179 ORDER BY p.dateline ASC, p.pid ASC 2180 LIMIT 1 2181 "); 2182 $oldthread = $db->fetch_array($query); 2183 $sqlarray = array( 2184 "subject" => $db->escape_string($oldthread['subject']), 2185 "replyto" => 0 2186 ); 2187 $db->update_query("posts", $sqlarray, "pid='{$oldthread['pid']}'"); 2188 } 2189 2190 foreach($counters as $key => $counter) 2191 { 2192 if($counter >= 0) 2193 { 2194 $counters[$key] = "+{$counter}"; 2195 } 2196 } 2197 update_thread_counters($tid, $counters); 2198 update_last_post($tid); 2199 } 2200 } 2201 2202 // Update forum counters 2203 if(!empty($forum_counters)) 2204 { 2205 foreach($forum_counters as $fid => $counters) 2206 { 2207 foreach($counters as $key => $counter) 2208 { 2209 if($counter >= 0) 2210 { 2211 $counters[$key] = "+{$counter}"; 2212 } 2213 } 2214 update_forum_counters($fid, $counters); 2215 update_forum_lastpost($fid); 2216 } 2217 } 2218 2219 return $newtid; 2220 } 2221 2222 /** 2223 * Move multiple threads to new forum 2224 * 2225 * @param array $tids Thread IDs 2226 * @param int $moveto Destination forum 2227 * @return boolean 2228 * 2229 * @deprecated Iterate over move_thread instead 2230 */ 2231 function move_threads($tids, $moveto) 2232 { 2233 global $db, $plugins; 2234 2235 // Make sure we only have valid values 2236 $tids = array_map('intval', $tids); 2237 2238 $tid_list = implode(',', $tids); 2239 2240 $moveto = (int)$moveto; 2241 2242 $newforum = get_forum($moveto); 2243 2244 if(empty($tids) || !$newforum) 2245 { 2246 return false; 2247 } 2248 2249 $total_posts = $total_unapproved_posts = $total_deleted_posts = $total_threads = $total_unapproved_threads = $total_deleted_threads = 0; 2250 $forum_counters = $user_counters = array(); 2251 $query = $db->simple_select("threads", "fid, visible, replies, unapprovedposts, deletedposts, tid, uid", "tid IN ($tid_list)"); 2252 while($thread = $db->fetch_array($query)) 2253 { 2254 $forum = get_forum($thread['fid']); 2255 2256 if(!isset($forum_counters[$thread['fid']])) 2257 { 2258 $forum_counters[$thread['fid']] = array( 2259 'posts' => 0, 2260 'threads' => 0, 2261 'unapprovedposts' => 0, 2262 'unapprovedthreads' => 0, 2263 'deletedthreads' => 0, 2264 'deletedposts' => 0 2265 ); 2266 } 2267 2268 if(!isset($user_counters[$thread['uid']])) 2269 { 2270 $user_counters[$thread['uid']] = array( 2271 'num_posts' => 0, 2272 'num_threads' => 0 2273 ); 2274 } 2275 2276 if($thread['visible'] == 1) 2277 { 2278 $total_posts += $thread['replies']+1; 2279 $total_unapproved_posts += $thread['unapprovedposts']; 2280 $total_deleted_posts += $thread['deletedposts']; 2281 $forum_counters[$thread['fid']]['posts'] += $thread['replies']+1; 2282 $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['unapprovedposts']; 2283 $forum_counters[$thread['fid']]['deletedposts'] += $thread['deletedposts']; 2284 2285 $forum_counters[$thread['fid']]['threads']++; 2286 ++$total_threads; 2287 2288 if($newforum['usethreadcounts'] == 1 && $forum['usethreadcounts'] == 0) 2289 { 2290 ++$user_counters[$thread['uid']]['num_threads']; 2291 } 2292 else if($newforum['usethreadcounts'] == 0 && $forum['usethreadcounts'] == 1) 2293 { 2294 --$user_counters[$thread['uid']]['num_threads']; 2295 } 2296 2297 $query1 = $db->query(" 2298 SELECT COUNT(p.pid) AS posts, u.uid 2299 FROM ".TABLE_PREFIX."posts p 2300 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 2301 WHERE p.tid = '{$thread['tid']}' AND p.visible=1 2302 GROUP BY u.uid 2303 ORDER BY posts DESC 2304 "); 2305 while($posters = $db->fetch_array($query1)) 2306 { 2307 if(!isset($user_counters[$posters['uid']])) 2308 { 2309 $user_counters[$posters['uid']] = array( 2310 'num_posts' => 0, 2311 'num_threads' => 0 2312 ); 2313 } 2314 2315 if($newforum['usepostcounts'] != 0 && $forum['usepostcounts'] == 0) 2316 { 2317 $user_counters[$posters['uid']]['num_posts'] += $posters['posts']; 2318 } 2319 else if($newforum['usepostcounts'] == 0 && $forum['usepostcounts'] != 0) 2320 { 2321 $user_counters[$posters['uid']]['num_posts'] -= $posters['posts']; 2322 } 2323 } 2324 } 2325 elseif($thread['visible'] == -1) 2326 { 2327 $total_deleted_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; 2328 2329 $forum_counters[$thread['fid']]['deletedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied deleted posts counter for deleted threads 2330 2331 $forum_counters[$thread['fid']]['deletedthreads']++; 2332 ++$total_deleted_threads; 2333 } 2334 else 2335 { 2336 $total_unapproved_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; 2337 2338 $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied unapproved posts counter for unapproved threads 2339 2340 $forum_counters[$thread['fid']]['unapprovedthreads']++; 2341 ++$total_unapproved_threads; 2342 } 2343 2344 // Remove old redirects 2345 $redirects_query = $db->simple_select('threads', 'tid', "closed='moved|{$thread['tid']}' AND fid='$moveto'"); 2346 while($redirect_tid = $db->fetch_field($redirects_query, 'tid')) 2347 { 2348 $this->delete_thread($redirect_tid); 2349 } 2350 } 2351 2352 $sqlarray = array( 2353 "fid" => $moveto, 2354 ); 2355 $db->update_query("threads", $sqlarray, "tid IN ($tid_list)"); 2356 $db->update_query("posts", $sqlarray, "tid IN ($tid_list)"); 2357 2358 // If any of the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix 2359 $query = $db->simple_select("threads", "tid, prefix", "tid IN ($tid_list) AND prefix != 0"); 2360 while($thread = $db->fetch_array($query)) 2361 { 2362 switch($db->type) 2363 { 2364 case "pgsql": 2365 case "sqlite": 2366 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 2367 break; 2368 default: 2369 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 2370 } 2371 if($db->fetch_field($query, "num_prefixes") == 0) 2372 { 2373 $sqlarray = array( 2374 "prefix" => 0, 2375 ); 2376 $db->update_query("threads", $sqlarray, "tid = '{$thread['tid']}'"); 2377 } 2378 } 2379 2380 $arguments = array("tids" => $tids, "moveto" => $moveto); 2381 $plugins->run_hooks("class_moderation_move_threads", $arguments); 2382 2383 if(!empty($user_counters)) 2384 { 2385 foreach($user_counters as $uid => $counters) 2386 { 2387 $update_array = array( 2388 "postnum" => "+{$counters['num_posts']}", 2389 "threadnum" => "+{$counters['num_threads']}", 2390 ); 2391 update_user_counters($uid, $update_array); 2392 } 2393 } 2394 2395 if(is_array($forum_counters)) 2396 { 2397 foreach($forum_counters as $fid => $counter) 2398 { 2399 $updated_count = array( 2400 'posts' => "-{$counter['posts']}", 2401 'threads' => "-{$counter['threads']}", 2402 'unapprovedposts' => "-{$counter['unapprovedposts']}", 2403 'unapprovedthreads' => "-{$counter['unapprovedthreads']}", 2404 'deletedposts' => "-{$counter['deletedposts']}", 2405 'deletedthreads' => "-{$counter['deletedthreads']}" 2406 2407 ); 2408 update_forum_counters($fid, $updated_count); 2409 update_forum_lastpost($fid); 2410 } 2411 } 2412 2413 $updated_count = array( 2414 "threads" => "+{$total_threads}", 2415 "unapprovedthreads" => "+{$total_unapproved_threads}", 2416 "posts" => "+{$total_posts}", 2417 "unapprovedposts" => "+{$total_unapproved_posts}", 2418 'deletedposts' => "+{$total_deleted_posts}", 2419 "deletedthreads" => "+{$total_deleted_threads}" 2420 ); 2421 2422 update_forum_counters($moveto, $updated_count); 2423 update_forum_lastpost($moveto); 2424 2425 // Remove thread subscriptions for the users who no longer have permission to view the thread 2426 $this->remove_thread_subscriptions($tid_list, false, $moveto); 2427 2428 return true; 2429 } 2430 2431 /** 2432 * Approve multiple posts 2433 * 2434 * @param array $pids PIDs 2435 * @return boolean 2436 */ 2437 function approve_posts($pids) 2438 { 2439 global $db, $cache, $plugins; 2440 2441 $num_posts = 0; 2442 2443 if(empty($pids)) 2444 { 2445 return false; 2446 } 2447 2448 // Make sure we only have valid values 2449 $pids = array_map('intval', $pids); 2450 2451 $pid_list = implode(',', $pids); 2452 $pids = $threads_to_update = array(); 2453 2454 // Make visible 2455 $approve = array( 2456 "visible" => 1, 2457 ); 2458 2459 // We have three cases we deal with in these code segments: 2460 // 1) We're approving specific unapproved posts 2461 // 1.1) if the thread is approved 2462 // 1.2) if the thread is unapproved 2463 // 2) We're approving the firstpost of the thread, therefore approving the thread itself 2464 // 3) We're doing both 1 and 2 2465 $query = $db->query(" 2466 SELECT p.tid 2467 FROM ".TABLE_PREFIX."posts p 2468 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 2469 WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost = p.pid AND t.visible = 0 2470 "); 2471 while($post = $db->fetch_array($query)) 2472 { 2473 // This is the first post in the thread so we're approving the whole thread. 2474 $threads_to_update[] = $post['tid']; 2475 } 2476 2477 if(!empty($threads_to_update)) 2478 { 2479 $this->approve_threads($threads_to_update); 2480 } 2481 2482 $thread_counters = $forum_counters = $user_counters = array(); 2483 2484 $query = $db->query(" 2485 SELECT p.pid, p.tid, p.fid, p.uid, t.visible AS threadvisible 2486 FROM ".TABLE_PREFIX."posts p 2487 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 2488 WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost != p.pid 2489 "); 2490 while($post = $db->fetch_array($query)) 2491 { 2492 $pids[] = $post['pid']; 2493 2494 if(!isset($thread_counters[$post['tid']])) 2495 { 2496 $thread_counters[$post['tid']] = array( 2497 'replies' => 0 2498 ); 2499 } 2500 2501 ++$thread_counters[$post['tid']]['replies']; 2502 2503 // If the thread of this post is unapproved then we've already taken into account this counter as implied. 2504 // Updating it again would cause it to double count 2505 if($post['threadvisible'] == 1) 2506 { 2507 if(!isset($forum_counters[$post['fid']])) 2508 { 2509 $forum_counters[$post['fid']] = array( 2510 'num_posts' => 0 2511 ); 2512 } 2513 ++$forum_counters[$post['fid']]['num_posts']; 2514 } 2515 2516 $forum = get_forum($post['fid']); 2517 2518 // If post counts enabled in this forum and the thread is approved, add 1 2519 if($forum['usepostcounts'] != 0 && $post['threadvisible'] == 1) 2520 { 2521 if(!isset($user_counters[$post['uid']])) 2522 { 2523 $user_counters[$post['uid']] = 0; 2524 } 2525 ++$user_counters[$post['uid']]; 2526 } 2527 } 2528 2529 if(empty($pids) && empty($threads_to_update)) 2530 { 2531 return false; 2532 } 2533 2534 if(!empty($pids)) 2535 { 2536 $where = "pid IN (".implode(',', $pids).")"; 2537 $db->update_query("posts", $approve, $where); 2538 } 2539 2540 $plugins->run_hooks("class_moderation_approve_posts", $pids); 2541 2542 if(!empty($thread_counters)) 2543 { 2544 foreach($thread_counters as $tid => $counters) 2545 { 2546 $counters_update = array( 2547 "unapprovedposts" => "-".$counters['replies'], 2548 "replies" => "+".$counters['replies'] 2549 ); 2550 update_thread_counters($tid, $counters_update); 2551 update_last_post($tid); 2552 } 2553 } 2554 2555 if(!empty($forum_counters)) 2556 { 2557 foreach($forum_counters as $fid => $counters) 2558 { 2559 $updated_forum_stats = array( 2560 'posts' => "+{$counters['num_posts']}", 2561 'unapprovedposts' => "-{$counters['num_posts']}", 2562 ); 2563 update_forum_counters($fid, $updated_forum_stats); 2564 update_forum_lastpost($fid); 2565 } 2566 } 2567 2568 if(!empty($user_counters)) 2569 { 2570 foreach($user_counters as $uid => $counter) 2571 { 2572 update_user_counters($uid, array('postnum' => "+{$counter}")); 2573 } 2574 } 2575 2576 return true; 2577 } 2578 2579 /** 2580 * Unapprove multiple posts 2581 * 2582 * @param array $pids PIDs 2583 * @return boolean 2584 */ 2585 function unapprove_posts($pids) 2586 { 2587 global $db, $cache, $plugins; 2588 2589 if(empty($pids)) 2590 { 2591 return false; 2592 } 2593 2594 // Make sure we only have valid values 2595 $pids = array_map('intval', $pids); 2596 2597 $pid_list = implode(',', $pids); 2598 $pids = $threads_to_update = array(); 2599 2600 // Make invisible 2601 $approve = array( 2602 "visible" => 0, 2603 ); 2604 2605 // We have three cases we deal with in these code segments: 2606 // 1) We're unapproving specific approved posts 2607 // 1.1) if the thread is approved 2608 // 1.2) if the thread is unapproved 2609 // 1.3) if the thread is deleted 2610 // 2) We're unapproving the firstpost of the thread, therefore unapproving the thread itself 2611 // 3) We're doing both 1 and 2 2612 $query = $db->query(" 2613 SELECT p.tid 2614 FROM ".TABLE_PREFIX."posts p 2615 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 2616 WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost = p.pid AND t.visible IN (-1,1) 2617 "); 2618 while($post = $db->fetch_array($query)) 2619 { 2620 // This is the first post in the thread so we're unapproving the whole thread. 2621 $threads_to_update[] = $post['tid']; 2622 } 2623 2624 if(!empty($threads_to_update)) 2625 { 2626 $this->unapprove_threads($threads_to_update); 2627 } 2628 2629 $thread_counters = $forum_counters = $user_counters = array(); 2630 2631 $query = $db->query(" 2632 SELECT p.pid, p.tid, p.visible, p.fid, p.uid, t.visible AS threadvisible 2633 FROM ".TABLE_PREFIX."posts p 2634 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 2635 WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost != p.pid 2636 "); 2637 while($post = $db->fetch_array($query)) 2638 { 2639 $pids[] = $post['pid']; 2640 2641 if(!isset($thread_counters[$post['tid']])) 2642 { 2643 $thread_counters[$post['tid']] = array( 2644 'replies' => 0, 2645 'unapprovedposts' => 0, 2646 'deletedposts' => 0 2647 ); 2648 } 2649 2650 ++$thread_counters[$post['tid']]['unapprovedposts']; 2651 if($post['visible'] == 1) 2652 { 2653 ++$thread_counters[$post['tid']]['replies']; 2654 } 2655 else 2656 { 2657 ++$thread_counters[$post['tid']]['deletedposts']; 2658 } 2659 2660 if(!isset($forum_counters[$post['fid']])) 2661 { 2662 $forum_counters[$post['fid']] = array( 2663 'num_posts' => 0, 2664 'num_unapproved_posts' => 0, 2665 'num_deleted_posts' => 0 2666 ); 2667 } 2668 2669 // If the thread of this post is unapproved then we've already taken into account this counter as implied. 2670 // Updating it again would cause it to double count 2671 if($post['threadvisible'] != 0) 2672 { 2673 ++$forum_counters[$post['fid']]['num_unapproved_posts']; 2674 if($post['visible'] == 1) 2675 { 2676 ++$forum_counters[$post['fid']]['num_posts']; 2677 } 2678 else 2679 { 2680 ++$forum_counters[$post['fid']]['num_deleted_posts']; 2681 } 2682 } 2683 2684 $forum = get_forum($post['fid']); 2685 2686 // If post counts enabled in this forum and the thread is approved, subtract 1 2687 if($forum['usepostcounts'] != 0 && $post['visible'] == 1 && $post['threadvisible'] == 1) 2688 { 2689 if(!isset($user_counters[$post['uid']])) 2690 { 2691 $user_counters[$post['uid']] = 0; 2692 } 2693 --$user_counters[$post['uid']]; 2694 } 2695 } 2696 2697 if(empty($pids) && empty($threads_to_update)) 2698 { 2699 return false; 2700 } 2701 2702 if(!empty($pids)) 2703 { 2704 $where = "pid IN (".implode(',', $pids).")"; 2705 $db->update_query("posts", $approve, $where); 2706 } 2707 2708 $plugins->run_hooks("class_moderation_unapprove_posts", $pids); 2709 2710 if(!empty($thread_counters)) 2711 { 2712 foreach($thread_counters as $tid => $counters) 2713 { 2714 $counters_update = array( 2715 "unapprovedposts" => "+".$counters['unapprovedposts'], 2716 "replies" => "-".$counters['replies'], 2717 "deletedposts" => "-".$counters['deletedposts'] 2718 ); 2719 2720 update_thread_counters($tid, $counters_update); 2721 update_last_post($tid); 2722 } 2723 } 2724 2725 if(!empty($forum_counters)) 2726 { 2727 foreach($forum_counters as $fid => $counters) 2728 { 2729 $updated_forum_stats = array( 2730 'posts' => "-{$counters['num_posts']}", 2731 'unapprovedposts' => "+{$counters['num_unapproved_posts']}", 2732 'deletedposts' => "-{$counters['num_deleted_posts']}" 2733 ); 2734 update_forum_counters($fid, $updated_forum_stats); 2735 update_forum_lastpost($fid); 2736 } 2737 } 2738 2739 if(!empty($user_counters)) 2740 { 2741 foreach($user_counters as $uid => $counter) 2742 { 2743 update_user_counters($uid, array('postnum' => "{$counter}")); 2744 } 2745 } 2746 2747 return true; 2748 } 2749 2750 /** 2751 * Change thread subject 2752 * 2753 * @param int|array $tids Thread ID(s) 2754 * @param string $format Format of new subject (with {subject}) 2755 * @return boolean 2756 */ 2757 function change_thread_subject($tids, $format) 2758 { 2759 global $db, $mybb, $plugins; 2760 2761 // Get tids into list 2762 if(!is_array($tids)) 2763 { 2764 $tids = array($tids); 2765 } 2766 2767 // Make sure we only have valid values 2768 $tids = array_map('intval', $tids); 2769 2770 if(empty($tids)) 2771 { 2772 return false; 2773 } 2774 2775 $tid_list = implode(',', $tids); 2776 2777 // Get original subject 2778 $query = $db->query(" 2779 SELECT u.uid, u.username, t.tid, t.subject FROM ".TABLE_PREFIX."threads t 2780 LEFT JOIN ".TABLE_PREFIX."users u ON t.uid=u.uid 2781 WHERE tid IN ($tid_list) 2782 "); 2783 while($thread = $db->fetch_array($query)) 2784 { 2785 // Update threads and first posts with new subject 2786 $find = array('{username}', 'author', '{subject}'); 2787 $replace = array($mybb->user['username'], $thread['username'], $thread['subject']); 2788 2789 $new_subject = str_ireplace($find, $replace, $format); 2790 2791 $args = array( 2792 'thread' => &$thread, 2793 'new_subject' => &$new_subject, 2794 ); 2795 2796 $plugins->run_hooks("class_moderation_change_thread_subject_newsubject", $args); 2797 2798 $update_subject = array( 2799 "subject" => $db->escape_string($new_subject) 2800 ); 2801 $db->update_query("threads", $update_subject, "tid='{$thread['tid']}'"); 2802 $db->update_query("posts", $update_subject, "tid='{$thread['tid']}' AND replyto='0'"); 2803 } 2804 2805 $arguments = array("tids" => $tids, "format" => $format); 2806 $plugins->run_hooks("class_moderation_change_thread_subject", $arguments); 2807 2808 return true; 2809 } 2810 2811 /** 2812 * Add thread expiry 2813 * 2814 * @param int $tid Thread ID 2815 * @param int $deletetime Timestamp when the thread is deleted 2816 * @return boolean 2817 */ 2818 function expire_thread($tid, $deletetime) 2819 { 2820 global $db, $plugins; 2821 2822 $tid = (int)$tid; 2823 2824 if(empty($tid)) 2825 { 2826 return false; 2827 } 2828 2829 $update_thread = array( 2830 "deletetime" => (int)$deletetime 2831 ); 2832 $db->update_query("threads", $update_thread, "tid='{$tid}'"); 2833 2834 $arguments = array("tid" => $tid, "deletetime" => $deletetime); 2835 $plugins->run_hooks("class_moderation_expire_thread", $arguments); 2836 2837 return true; 2838 } 2839 2840 /** 2841 * Toggle post visibility (approved/unapproved) 2842 * 2843 * @param array $pids Post IDs 2844 * @return boolean true 2845 */ 2846 function toggle_post_visibility($pids) 2847 { 2848 global $db; 2849 2850 // Make sure we only have valid values 2851 $pids = array_map('intval', $pids); 2852 2853 $pid_list = implode(',', $pids); 2854 $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)"); 2855 while($post = $db->fetch_array($query)) 2856 { 2857 if($post['visible'] != 0) 2858 { 2859 $unapprove[] = $post['pid']; 2860 } 2861 else 2862 { 2863 $approve[] = $post['pid']; 2864 } 2865 } 2866 if(is_array($unapprove)) 2867 { 2868 $this->unapprove_posts($unapprove); 2869 } 2870 if(is_array($approve)) 2871 { 2872 $this->approve_posts($approve); 2873 } 2874 return true; 2875 } 2876 2877 /** 2878 * Toggle post visibility (deleted/restored) 2879 * 2880 * @param array $pids Post IDs 2881 * @return boolean true 2882 */ 2883 function toggle_post_softdelete($pids) 2884 { 2885 global $db; 2886 2887 // Make sure we only have valid values 2888 $pids = array_map('intval', $pids); 2889 2890 $pid_list = implode(',', $pids); 2891 $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)"); 2892 while($post = $db->fetch_array($query)) 2893 { 2894 if($post['visible'] != -1) 2895 { 2896 $delete[] = $post['pid']; 2897 } 2898 else 2899 { 2900 $restore[] = $post['pid']; 2901 } 2902 } 2903 if(is_array($delete)) 2904 { 2905 $this->soft_delete_posts($delete); 2906 } 2907 if(is_array($restore)) 2908 { 2909 $this->restore_posts($restore); 2910 } 2911 return true; 2912 } 2913 2914 /** 2915 * Toggle thread visibility (approved/unapproved) 2916 * 2917 * @param array $tids Thread IDs 2918 * @param int $fid Forum ID 2919 * @return boolean true 2920 */ 2921 function toggle_thread_visibility($tids, $fid) 2922 { 2923 global $db; 2924 2925 // Make sure we only have valid values 2926 $tids = array_map('intval', $tids); 2927 $fid = (int)$fid; 2928 2929 $tid_list = implode(',', $tids); 2930 $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)"); 2931 while($thread = $db->fetch_array($query)) 2932 { 2933 if($thread['visible'] != 0) 2934 { 2935 $unapprove[] = $thread['tid']; 2936 } 2937 else 2938 { 2939 $approve[] = $thread['tid']; 2940 } 2941 } 2942 if(is_array($unapprove)) 2943 { 2944 $this->unapprove_threads($unapprove, $fid); 2945 } 2946 if(is_array($approve)) 2947 { 2948 $this->approve_threads($approve, $fid); 2949 } 2950 return true; 2951 } 2952 2953 /** 2954 * Toggle thread visibility (deleted/restored) 2955 * 2956 * @param array $tids Thread IDs 2957 * @return boolean true 2958 */ 2959 function toggle_thread_softdelete($tids) 2960 { 2961 global $db; 2962 2963 // Make sure we only have valid values 2964 $tids = array_map('intval', $tids); 2965 2966 $tid_list = implode(',', $tids); 2967 $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)"); 2968 while($thread = $db->fetch_array($query)) 2969 { 2970 if($thread['visible'] != -1) 2971 { 2972 $delete[] = $thread['tid']; 2973 } 2974 else 2975 { 2976 $restore[] = $thread['tid']; 2977 } 2978 } 2979 if(is_array($delete)) 2980 { 2981 $this->soft_delete_threads($delete); 2982 } 2983 if(is_array($restore)) 2984 { 2985 $this->restore_threads($restore); 2986 } 2987 return true; 2988 } 2989 2990 /** 2991 * Toggle threads open/closed 2992 * 2993 * @param array $tids Thread IDs 2994 * @return boolean true 2995 */ 2996 function toggle_thread_status($tids) 2997 { 2998 global $db; 2999 3000 // Make sure we only have valid values 3001 $tids = array_map('intval', $tids); 3002 3003 $tid_list = implode(',', $tids); 3004 $query = $db->simple_select("threads", 'tid, closed', "tid IN ($tid_list)"); 3005 while($thread = $db->fetch_array($query)) 3006 { 3007 if($thread['closed'] == 1) 3008 { 3009 $open[] = $thread['tid']; 3010 } 3011 elseif($thread['closed'] == 0) 3012 { 3013 $close[] = $thread['tid']; 3014 } 3015 } 3016 if(is_array($open)) 3017 { 3018 $this->open_threads($open); 3019 } 3020 if(is_array($close)) 3021 { 3022 $this->close_threads($close); 3023 } 3024 return true; 3025 } 3026 3027 /** 3028 * Toggle threads stick/unstick 3029 * 3030 * @param array $tids Thread IDs 3031 * @return boolean true 3032 */ 3033 function toggle_thread_importance($tids) 3034 { 3035 global $db; 3036 3037 // Make sure we only have valid values 3038 $tids = array_map('intval', $tids); 3039 3040 $stick = array(); 3041 $unstick = array(); 3042 3043 $tid_list = implode(',', $tids); 3044 $query = $db->simple_select("threads", 'tid, sticky', "tid IN ($tid_list)"); 3045 while($thread = $db->fetch_array($query)) 3046 { 3047 if($thread['sticky'] == 0) 3048 { 3049 $stick[] = $thread['tid']; 3050 } 3051 elseif($thread['sticky'] == 1) 3052 { 3053 $unstick[] = $thread['tid']; 3054 } 3055 } 3056 if(!empty($stick)) 3057 { 3058 $this->stick_threads($stick); 3059 } 3060 if(!empty($unstick)) 3061 { 3062 $this->unstick_threads($unstick); 3063 } 3064 return true; 3065 } 3066 3067 /** 3068 * Remove thread subscriptions (from one or multiple threads in the same forum) 3069 * 3070 * @param int|array $tids Thread ID, or an array of thread IDs from the same forum. 3071 * @param boolean $all True (default) to delete all subscriptions, false to only delete subscriptions from users with no permission to read the thread 3072 * @param int $fid (Only applies if $all is false) The forum ID of the thread 3073 * @return boolean 3074 */ 3075 function remove_thread_subscriptions($tids, $all = true, $fid = 0) 3076 { 3077 global $db, $plugins; 3078 3079 // Format thread IDs 3080 if(!is_array($tids)) 3081 { 3082 $tids = array($tids); 3083 } 3084 3085 if(empty($tids)) 3086 { 3087 return false; 3088 } 3089 3090 // Make sure we only have valid values 3091 $tids = array_map('intval', $tids); 3092 $fid = (int)$fid; 3093 3094 $tids_csv = implode(',', $tids); 3095 3096 // Delete only subscriptions from users who no longer have permission to read the thread. 3097 if(!$all) 3098 { 3099 // Get groups that cannot view the forum or its threads 3100 $forum_parentlist = get_parent_list($fid); 3101 $query = $db->simple_select("forumpermissions", "gid", "fid IN ({$forum_parentlist}) AND (canview=0 OR canviewthreads=0)"); 3102 $groups = array(); 3103 $additional_groups = ''; 3104 while($group = $db->fetch_array($query)) 3105 { 3106 $groups[] = $group['gid']; 3107 switch($db->type) 3108 { 3109 case "pgsql": 3110 case "sqlite": 3111 $additional_groups .= " OR ','||u.additionalgroups||',' LIKE ',{$group['gid']},'"; 3112 break; 3113 default: 3114 $additional_groups .= " OR CONCAT(',',u.additionalgroups,',') LIKE ',{$group['gid']},'"; 3115 } 3116 } 3117 // If there are groups found, delete subscriptions from users in these groups 3118 if(count($groups) > 0) 3119 { 3120 $groups_csv = implode(',', $groups); 3121 $query = $db->query(" 3122 SELECT s.tid, u.uid 3123 FROM ".TABLE_PREFIX."threadsubscriptions s 3124 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=s.uid) 3125 WHERE s.tid IN ({$tids_csv}) 3126 AND (u.usergroup IN ({$groups_csv}){$additional_groups}) 3127 "); 3128 while($subscription = $db->fetch_array($query)) 3129 { 3130 $db->delete_query("threadsubscriptions", "uid='{$subscription['uid']}' AND tid='{$subscription['tid']}'"); 3131 } 3132 } 3133 } 3134 // Delete all subscriptions of this thread 3135 else 3136 { 3137 $db->delete_query("threadsubscriptions", "tid IN ({$tids_csv})"); 3138 } 3139 3140 $arguments = array("tids" => $tids, "all" => $all, "fid" => $fid); 3141 $plugins->run_hooks("class_moderation_remove_thread_subscriptions", $arguments); 3142 3143 return true; 3144 } 3145 3146 /** 3147 * Apply a thread prefix (to one or multiple threads in the same forum) 3148 * 3149 * @param int|array $tids Thread ID, or an array of thread IDs from the same forum. 3150 * @param int $prefix Prefix ID to apply to the threads 3151 * @return bool 3152 */ 3153 function apply_thread_prefix($tids, $prefix = 0) 3154 { 3155 global $db, $plugins; 3156 3157 // Format thread IDs 3158 if(!is_array($tids)) 3159 { 3160 $tids = array($tids); 3161 } 3162 3163 if(empty($tids)) 3164 { 3165 return false; 3166 } 3167 3168 // Make sure we only have valid values 3169 $tids = array_map('intval', $tids); 3170 $tids_csv = implode(',', $tids); 3171 3172 $update_thread = array('prefix' => (int)$prefix); 3173 $db->update_query('threads', $update_thread, "tid IN ({$tids_csv})"); 3174 3175 $arguments = array('tids' => $tids, 'prefix' => $prefix); 3176 3177 $plugins->run_hooks('class_moderation_apply_thread_prefix', $arguments); 3178 3179 return true; 3180 } 3181 3182 /** 3183 * Soft delete multiple posts 3184 * 3185 * @param array $pids PIDs 3186 * @return boolean 3187 */ 3188 function soft_delete_posts($pids) 3189 { 3190 global $db, $cache, $plugins; 3191 3192 if(empty($pids)) 3193 { 3194 return false; 3195 } 3196 3197 // Make sure we only have valid values 3198 $pids = array_map('intval', $pids); 3199 3200 $pid_list = implode(',', $pids); 3201 $pids = $threads_to_update = array(); 3202 3203 // Make invisible 3204 $update = array( 3205 "visible" => -1, 3206 ); 3207 3208 // We have three cases we deal with in these code segments: 3209 // 1) We're deleting specific approved posts 3210 // 1.1) if the thread is approved 3211 // 1.2) if the thread is unapproved 3212 // 1.3) if the thread is deleted 3213 // 2) We're deleting the firstpost of the thread, therefore deleting the thread itself 3214 // 3) We're doing both 1 and 2 3215 $query = $db->query(" 3216 SELECT p.tid 3217 FROM ".TABLE_PREFIX."posts p 3218 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 3219 WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost = p.pid AND t.visible IN (0,1) 3220 "); 3221 while($post = $db->fetch_array($query)) 3222 { 3223 // This is the first post in the thread so we're deleting the whole thread. 3224 $threads_to_update[] = $post['tid']; 3225 } 3226 3227 if(!empty($threads_to_update)) 3228 { 3229 $this->soft_delete_threads($threads_to_update); 3230 } 3231 3232 $thread_counters = $forum_counters = $user_counters = array(); 3233 3234 $query = $db->query(" 3235 SELECT p.pid, p.tid, p.visible, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible 3236 FROM ".TABLE_PREFIX."posts p 3237 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 3238 LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) 3239 WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost != p.pid 3240 "); 3241 while($post = $db->fetch_array($query)) 3242 { 3243 $pids[] = $post['pid']; 3244 3245 if(!isset($thread_counters[$post['tid']])) 3246 { 3247 $thread_counters[$post['tid']] = array( 3248 'replies' => 0, 3249 'unapprovedposts' => 0, 3250 'deletedposts' => 0 3251 ); 3252 } 3253 3254 ++$thread_counters[$post['tid']]['deletedposts']; 3255 if($post['visible'] == 1) 3256 { 3257 ++$thread_counters[$post['tid']]['replies']; 3258 } 3259 else 3260 { 3261 ++$thread_counters[$post['tid']]['unapprovedposts']; 3262 } 3263 3264 if(!isset($forum_counters[$post['fid']])) 3265 { 3266 $forum_counters[$post['fid']] = array( 3267 'num_posts' => 0, 3268 'num_unapproved_posts' => 0, 3269 'num_deleted_posts' => 0 3270 ); 3271 } 3272 3273 // If the thread of this post is deleted then we've already taken into account this counter as implied. 3274 // Updating it again would cause it to double count 3275 if($post['threadvisible'] == 1) 3276 { 3277 ++$forum_counters[$post['fid']]['num_deleted_posts']; 3278 if($post['visible'] == 1) 3279 { 3280 ++$forum_counters[$post['fid']]['num_posts']; 3281 } 3282 else 3283 { 3284 ++$forum_counters[$post['fid']]['num_unapproved_posts']; 3285 } 3286 } 3287 3288 // If post counts enabled in this forum and the thread is approved, subtract 1 3289 if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1 && $post['visible'] == 1) 3290 { 3291 if(!isset($user_counters[$post['uid']])) 3292 { 3293 $user_counters[$post['uid']] = 0; 3294 } 3295 --$user_counters[$post['uid']]; 3296 } 3297 } 3298 3299 if(empty($pids) && empty($threads_to_update)) 3300 { 3301 return false; 3302 } 3303 3304 if(!empty($pids)) 3305 { 3306 $where = "pid IN (".implode(',', $pids).")"; 3307 $db->update_query("posts", $update, $where); 3308 mark_reports($pids, "posts"); 3309 } 3310 3311 $plugins->run_hooks("class_moderation_soft_delete_posts", $pids); 3312 3313 if(is_array($thread_counters)) 3314 { 3315 foreach($thread_counters as $tid => $counters) 3316 { 3317 $counters_update = array( 3318 "unapprovedposts" => "-".$counters['unapprovedposts'], 3319 "replies" => "-".$counters['replies'], 3320 "deletedposts" => "+".$counters['deletedposts'] 3321 ); 3322 3323 update_thread_counters($tid, $counters_update); 3324 update_last_post($tid); 3325 } 3326 } 3327 3328 if(is_array($forum_counters)) 3329 { 3330 foreach($forum_counters as $fid => $counters) 3331 { 3332 $updated_forum_stats = array( 3333 'posts' => "-{$counters['num_posts']}", 3334 'unapprovedposts' => "-{$counters['num_unapproved_posts']}", 3335 'deletedposts' => "+{$counters['num_deleted_posts']}" 3336 ); 3337 update_forum_counters($fid, $updated_forum_stats); 3338 update_forum_lastpost($fid); 3339 } 3340 } 3341 3342 if(!empty($user_counters)) 3343 { 3344 foreach($user_counters as $uid => $counter) 3345 { 3346 update_user_counters($uid, array('postnum' => "{$counter}")); 3347 } 3348 } 3349 3350 return true; 3351 } 3352 3353 /** 3354 * Restore multiple posts 3355 * 3356 * @param array $pids PIDs 3357 * @return boolean 3358 */ 3359 function restore_posts($pids) 3360 { 3361 global $db, $cache, $plugins; 3362 3363 $num_posts = 0; 3364 3365 if(empty($pids)) 3366 { 3367 return false; 3368 } 3369 3370 // Make sure we only have valid values 3371 $pids = array_map('intval', $pids); 3372 3373 $pid_list = implode(',', $pids); 3374 $pids = $threads_to_update = array(); 3375 3376 // Make visible 3377 $update = array( 3378 "visible" => 1, 3379 ); 3380 3381 // We have three cases we deal with in these code segments: 3382 // 1) We're approving specific restored posts 3383 // 1.1) if the thread is deleted 3384 // 1.2) if the thread is restored 3385 // 2) We're restoring the firstpost of the thread, therefore restoring the thread itself 3386 // 3) We're doing both 1 and 2 3387 $query = $db->query(" 3388 SELECT p.tid 3389 FROM ".TABLE_PREFIX."posts p 3390 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 3391 WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost = p.pid AND t.visible = -1 3392 "); 3393 while($post = $db->fetch_array($query)) 3394 { 3395 // This is the first post in the thread so we're approving the whole thread. 3396 $threads_to_update[] = $post['tid']; 3397 } 3398 3399 if(!empty($threads_to_update)) 3400 { 3401 $this->restore_threads($threads_to_update); 3402 } 3403 3404 $thread_counters = $forum_counters = $user_counters = array(); 3405 3406 $query = $db->query(" 3407 SELECT p.pid, p.tid, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible 3408 FROM ".TABLE_PREFIX."posts p 3409 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 3410 LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) 3411 WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost != p.pid 3412 "); 3413 while($post = $db->fetch_array($query)) 3414 { 3415 $pids[] = $post['pid']; 3416 3417 if(!isset($thread_counters[$post['tid']])) 3418 { 3419 $thread_counters[$post['tid']] = array( 3420 'replies' => 0 3421 ); 3422 } 3423 3424 ++$thread_counters[$post['tid']]['replies']; 3425 3426 // If the thread of this post is deleted then we've already taken into account this counter as implied. 3427 // Updating it again would cause it to double count 3428 if($post['threadvisible'] == 1) 3429 { 3430 if(!isset($forum_counters[$post['fid']])) 3431 { 3432 $forum_counters[$post['fid']] = array( 3433 'num_posts' => 0 3434 ); 3435 } 3436 ++$forum_counters[$post['fid']]['num_posts']; 3437 } 3438 3439 // If post counts enabled in this forum and the thread is approved, add 1 3440 if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1) 3441 { 3442 if(!isset($user_counters[$post['uid']])) 3443 { 3444 $user_counters[$post['uid']] = 0; 3445 } 3446 ++$user_counters[$post['uid']]; 3447 3448 } 3449 } 3450 3451 if(empty($pids) && empty($threads_to_update)) 3452 { 3453 return false; 3454 } 3455 3456 if(!empty($pids)) 3457 { 3458 $where = "pid IN (".implode(',', $pids).")"; 3459 $db->update_query("posts", $update, $where); 3460 } 3461 3462 $plugins->run_hooks("class_moderation_restore_posts", $pids); 3463 3464 if(is_array($thread_counters)) 3465 { 3466 foreach($thread_counters as $tid => $counters) 3467 { 3468 $counters_update = array( 3469 "deletedposts" => "-".$counters['replies'], 3470 "replies" => "+".$counters['replies'] 3471 ); 3472 update_thread_counters($tid, $counters_update); 3473 update_last_post($tid); 3474 } 3475 } 3476 3477 if(is_array($forum_counters)) 3478 { 3479 foreach($forum_counters as $fid => $counters) 3480 { 3481 $updated_forum_stats = array( 3482 'posts' => "+{$counters['num_posts']}", 3483 'deletedposts' => "-{$counters['num_posts']}" 3484 ); 3485 update_forum_counters($fid, $updated_forum_stats); 3486 update_forum_lastpost($fid); 3487 } 3488 } 3489 3490 if(!empty($user_counters)) 3491 { 3492 foreach($user_counters as $uid => $counter) 3493 { 3494 update_user_counters($uid, array('postnum' => "+{$counter}")); 3495 } 3496 } 3497 3498 return true; 3499 } 3500 3501 /** 3502 * Restore one or more threads 3503 * 3504 * @param array|int $tids Thread ID(s) 3505 * @return boolean true 3506 */ 3507 function restore_threads($tids) 3508 { 3509 global $db, $cache, $plugins; 3510 3511 if(!is_array($tids)) 3512 { 3513 $tids = array($tids); 3514 } 3515 3516 if(empty($tids)) 3517 { 3518 return false; 3519 } 3520 3521 // Make sure we only have valid values 3522 $tids = array_map('intval', $tids); 3523 3524 $tid_list = $forum_counters = $user_counters = $posts_to_restore = array(); 3525 3526 $tids_list = implode(",", $tids); 3527 $query = $db->simple_select("threads", "*", "tid IN ($tids_list)"); 3528 3529 while($thread = $db->fetch_array($query)) 3530 { 3531 if($thread['visible'] != -1) 3532 { 3533 continue; 3534 } 3535 $tid_list[] = $thread['tid']; 3536 3537 $forum = get_forum($thread['fid']); 3538 3539 if(!isset($forum_counters[$forum['fid']])) 3540 { 3541 $forum_counters[$forum['fid']] = array( 3542 'num_posts' => 0, 3543 'num_threads' => 0, 3544 'num_deleted_posts' => 0, 3545 'num_unapproved_posts' => 0 3546 ); 3547 } 3548 3549 if(!isset($user_counters[$thread['uid']])) 3550 { 3551 $user_counters[$thread['uid']] = array( 3552 'num_posts' => 0, 3553 'num_threads' => 0 3554 ); 3555 } 3556 3557 ++$forum_counters[$forum['fid']]['num_threads']; 3558 $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Remove implied visible from count 3559 $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1; 3560 $forum_counters[$forum['fid']]['num_unapproved_posts'] += $thread['unapprovedposts']; 3561 3562 if($forum['usepostcounts'] != 0) 3563 { 3564 // On approving thread restore user post counts 3565 $query2 = $db->simple_select("posts", "COUNT(pid) as posts, uid", "tid='{$thread['tid']}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid"); 3566 while($counter = $db->fetch_array($query2)) 3567 { 3568 if(!isset($user_counters[$counter['uid']]['num_posts'])) 3569 { 3570 $user_counters[$counter['uid']]['num_posts'] = 0; 3571 } 3572 $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; 3573 } 3574 } 3575 3576 if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') 3577 { 3578 ++$user_counters[$thread['uid']]['num_threads']; 3579 } 3580 3581 $posts_to_restore[] = $thread['firstpost']; 3582 } 3583 3584 if(!empty($tid_list)) 3585 { 3586 $tid_moved_list = ""; 3587 $comma = ""; 3588 foreach($tid_list as $tid) 3589 { 3590 $tid_moved_list .= "{$comma}'moved|{$tid}'"; 3591 $comma = ","; 3592 } 3593 $tid_list = implode(',', $tid_list); 3594 $update = array( 3595 "visible" => 1 3596 ); 3597 $db->update_query("threads", $update, "tid IN ($tid_list)"); 3598 // Restore redirects, too 3599 $redirect_tids = array(); 3600 $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); 3601 while($redirect_tid = $db->fetch_field($query, 'tid')) 3602 { 3603 $redirect_tids[] = $redirect_tid; 3604 } 3605 if(!empty($redirect_tids)) 3606 { 3607 $this->restore_threads($redirect_tids); 3608 } 3609 if(!empty($posts_to_restore)) 3610 { 3611 $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_restore).")"); 3612 } 3613 3614 $plugins->run_hooks("class_moderation_restore_threads", $tids); 3615 3616 if(is_array($forum_counters)) 3617 { 3618 foreach($forum_counters as $fid => $counters) 3619 { 3620 // Update stats 3621 $update_array = array( 3622 "threads" => "+{$counters['num_threads']}", 3623 "posts" => "+{$counters['num_posts']}", 3624 "unapprovedposts" => "+{$counters['num_unapproved_posts']}", 3625 "deletedposts" => "-{$counters['num_deleted_posts']}", 3626 "deletedthreads" => "-{$counters['num_threads']}" 3627 ); 3628 update_forum_counters($fid, $update_array); 3629 update_forum_lastpost($fid); 3630 } 3631 } 3632 3633 if(!empty($user_counters)) 3634 { 3635 foreach($user_counters as $uid => $counters) 3636 { 3637 $update_array = array( 3638 "postnum" => "+{$counters['num_posts']}", 3639 "threadnum" => "+{$counters['num_threads']}", 3640 ); 3641 update_user_counters($uid, $update_array); 3642 } 3643 } 3644 } 3645 return true; 3646 } 3647 3648 /** 3649 * Soft delete one or more threads 3650 * 3651 * @param array|int Thread ID(s) 3652 * @return boolean 3653 */ 3654 function soft_delete_threads($tids) 3655 { 3656 global $db, $cache, $plugins; 3657 3658 if(!is_array($tids)) 3659 { 3660 $tids = array($tids); 3661 } 3662 3663 if(empty($tids)) 3664 { 3665 return false; 3666 } 3667 3668 // Make sure we only have valid values 3669 $tids = array_map('intval', $tids); 3670 3671 $tid_list = implode(',', $tids); 3672 $tid_moved_list = ""; 3673 $comma = ""; 3674 foreach($tids as $tid) 3675 { 3676 $tid_moved_list .= "{$comma}'moved|{$tid}'"; 3677 $comma = ","; 3678 } 3679 3680 $forum_counters = $user_counters = $posts_to_delete = array(); 3681 3682 $tids_list = implode(",", $tids); 3683 $query = $db->simple_select("threads", "*", "tid IN ($tids_list)"); 3684 3685 while($thread = $db->fetch_array($query)) 3686 { 3687 $forum = get_forum($thread['fid']); 3688 3689 if($thread['visible'] == 1 || $thread['visible'] == 0) 3690 { 3691 if(!isset($forum_counters[$forum['fid']])) 3692 { 3693 $forum_counters[$forum['fid']] = array( 3694 'num_posts' => 0, 3695 'num_threads' => 0, 3696 'num_deleted_threads' => 0, 3697 'num_deleted_posts' => 0, 3698 'unapproved_threads' => 0, 3699 'unapproved_posts' => 0 3700 ); 3701 } 3702 3703 if(!isset($user_counters[$thread['uid']])) 3704 { 3705 $user_counters[$thread['uid']] = array( 3706 'num_posts' => 0, 3707 'num_threads' => 0 3708 ); 3709 } 3710 3711 ++$forum_counters[$forum['fid']]['num_deleted_threads']; 3712 $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1; 3713 3714 if($thread['visible'] == 1) 3715 { 3716 ++$forum_counters[$forum['fid']]['num_threads']; 3717 $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Add implied invisible to count 3718 $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['unapprovedposts']; 3719 } 3720 else 3721 { 3722 ++$forum_counters[$forum['fid']]['unapproved_threads']; 3723 $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['replies']+$thread['deletedposts']+$thread['unapprovedposts']+1; // Add implied invisible to count 3724 $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['deletedposts']; 3725 } 3726 3727 // On unapproving thread update user post counts 3728 if($thread['visible'] == 1 && $forum['usepostcounts'] != 0) 3729 { 3730 $query2 = $db->simple_select("posts", "COUNT(pid) AS posts, uid", "tid='{$thread['tid']}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid"); 3731 while($counter = $db->fetch_array($query2)) 3732 { 3733 if(!isset($user_counters[$counter['uid']]['num_posts'])) 3734 { 3735 $user_counters[$counter['uid']]['num_posts'] = 0; 3736 } 3737 $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; 3738 } 3739 } 3740 3741 if($thread['visible'] == 1 && $forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') 3742 { 3743 ++$user_counters[$thread['uid']]['num_threads']; 3744 } 3745 } 3746 $posts_to_delete[] = $thread['firstpost']; 3747 } 3748 3749 $update = array( 3750 "visible" => -1 3751 ); 3752 $db->update_query("threads", $update, "tid IN ($tid_list)"); 3753 // Soft delete redirects, too 3754 $redirect_tids = array(); 3755 $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); 3756 3757 mark_reports($tids, "threads"); 3758 3759 while($redirect_tid = $db->fetch_field($query, 'tid')) 3760 { 3761 $redirect_tids[] = $redirect_tid; 3762 } 3763 if(!empty($redirect_tids)) 3764 { 3765 $this->soft_delete_threads($redirect_tids); 3766 } 3767 if(!empty($posts_to_delete)) 3768 { 3769 $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_delete).")"); 3770 } 3771 3772 $plugins->run_hooks("class_moderation_soft_delete_threads", $tids); 3773 3774 if(is_array($forum_counters)) 3775 { 3776 foreach($forum_counters as $fid => $counters) 3777 { 3778 // Update stats 3779 $update_array = array( 3780 "threads" => "-{$counters['num_threads']}", 3781 "unapprovedthreads" => "-{$counters['unapproved_threads']}", 3782 "posts" => "-{$counters['num_posts']}", 3783 "unapprovedposts" => "-{$counters['unapproved_posts']}", 3784 "deletedposts" => "+{$counters['num_deleted_posts']}", 3785 "deletedthreads" => "+{$counters['num_deleted_threads']}" 3786 ); 3787 update_forum_counters($fid, $update_array); 3788 update_forum_lastpost($fid); 3789 } 3790 } 3791 3792 if(!empty($user_counters)) 3793 { 3794 foreach($user_counters as $uid => $counters) 3795 { 3796 $update_array = array( 3797 "postnum" => "-{$counters['num_posts']}", 3798 "threadnum" => "-{$counters['num_threads']}", 3799 ); 3800 update_user_counters($uid, $update_array); 3801 } 3802 } 3803 3804 return true; 3805 } 3806 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup | Cross-referenced by PHPXref |