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