[ Index ] |
PHP Cross Reference of MyBB 1.8.38 |
[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 // Attach moved posts to the first post 1599 $db->update_query("posts", array('replyto' => $new_firstpost['pid']), "tid='{$tid}' AND replyto = 0 AND pid != '{$new_firstpost['pid']}'"); 1600 1601 // Update thread count if thread has a new firstpost and is visible 1602 if($thread['uid'] != $new_firstpost['uid'] && $thread['visible'] == 1 && $forum_cache[$thread['fid']]['usethreadcounts'] == 1) 1603 { 1604 if(!isset($user_posts[$thread['uid']]['threadnum'])) 1605 { 1606 $user_posts[$thread['uid']]['threadnum'] = 0; 1607 } 1608 --$user_posts[$thread['uid']]['threadnum']; 1609 if(!isset($user_posts[$new_firstpost['uid']]['threadnum'])) 1610 { 1611 $user_posts[$new_firstpost['uid']]['threadnum'] = 0; 1612 } 1613 ++$user_posts[$new_firstpost['uid']]['threadnum']; 1614 } 1615 1616 // Thread is not in current forum 1617 if($mergethread['fid'] != $thread['fid']) 1618 { 1619 // If new thread is unapproved, implied counter comes in to effect 1620 if($thread['visible'] == 0) 1621 { 1622 $updated_stats = array( 1623 "unapprovedposts" => '+'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts']) 1624 ); 1625 } 1626 elseif($thread['visible'] == -1) 1627 { 1628 $updated_stats = array( 1629 "deletedposts" => '+'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts']) 1630 ); 1631 } 1632 else 1633 { 1634 $updated_stats = array( 1635 "posts" => "+{$mergethread['replies']}", 1636 "unapprovedposts" => "+{$mergethread['unapprovedposts']}", 1637 "deletedposts" => "+{$mergethread['deletedposts']}" 1638 ); 1639 } 1640 update_forum_counters($thread['fid'], $updated_stats); 1641 1642 // If old thread is unapproved, implied counter comes in to effect 1643 if($mergethread['visible'] == 0) 1644 { 1645 $updated_stats = array( 1646 "unapprovedposts" => '-'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts']) 1647 ); 1648 } 1649 elseif($mergethread['visible'] == -1) 1650 { 1651 $updated_stats = array( 1652 "deletedposts" => '-'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts']) 1653 ); 1654 } 1655 else 1656 { 1657 $updated_stats = array( 1658 "posts" => "-{$mergethread['replies']}", 1659 "unapprovedposts" => "-{$mergethread['unapprovedposts']}", 1660 "deletedposts" => "-{$mergethread['deletedposts']}" 1661 ); 1662 } 1663 update_forum_counters($mergethread['fid'], $updated_stats); 1664 update_forum_lastpost($mergethread['fid']); 1665 } 1666 // Visibility changed 1667 elseif($mergethread['visible'] != $thread['visible']) 1668 { 1669 $updated_stats = array( 1670 'posts' => 0, 1671 'unapprovedposts' => 0, 1672 'deletedposts' => 0 1673 ); 1674 1675 // If old thread is unapproved, implied counter comes in to effect 1676 if($mergethread['visible'] == 0) 1677 { 1678 $updated_stats['unapprovedposts'] -= $mergethread['replies']+$mergethread['deletedposts']; 1679 $updated_stats['posts'] += $mergethread['replies']; 1680 $updated_stats['deletedposts'] += $mergethread['deletedposts']; 1681 } 1682 elseif($mergethread['visible'] == -1) 1683 { 1684 $updated_stats['deletedposts'] -= $mergethread['replies']+$mergethread['unapprovedposts']; 1685 $updated_stats['posts'] += $mergethread['replies']; 1686 $updated_stats['unapprovedposts'] += $mergethread['unapprovedposts']; 1687 } 1688 1689 // If new thread is unapproved, implied counter comes in to effect 1690 if($thread['visible'] == 0) 1691 { 1692 $updated_stats['unapprovedposts'] += $mergethread['replies']+$mergethread['deletedposts']; 1693 $updated_stats['posts'] -= $mergethread['replies']; 1694 $updated_stats['deletedposts'] -= $mergethread['deletedposts']; 1695 } 1696 elseif($thread['visible'] == -1) 1697 { 1698 $updated_stats['deletedposts'] += $mergethread['replies']+$mergethread['unapprovedposts']; 1699 $updated_stats['posts'] -= $mergethread['replies']; 1700 $updated_stats['unapprovedposts'] -= $mergethread['unapprovedposts']; 1701 } 1702 1703 $new_stats = array(); 1704 if($updated_stats['posts'] < 0) 1705 { 1706 $new_stats['posts'] = $updated_stats['posts']; 1707 } 1708 elseif($updated_stats['posts'] > 0) 1709 { 1710 $new_stats['posts'] = "+{$updated_stats['posts']}"; 1711 } 1712 1713 if($updated_stats['unapprovedposts'] < 0) 1714 { 1715 $new_stats['unapprovedposts'] = $updated_stats['unapprovedposts']; 1716 } 1717 elseif($updated_stats['unapprovedposts'] > 0) 1718 { 1719 $new_stats['unapprovedposts'] = "+{$updated_stats['unapprovedposts']}"; 1720 } 1721 1722 if($updated_stats['deletedposts'] < 0) 1723 { 1724 $new_stats['deletedposts'] = $updated_stats['deletedposts']; 1725 } 1726 elseif($updated_stats['deletedposts'] > 0) 1727 { 1728 $new_stats['deletedposts'] = "+{$updated_stats['deletedposts']}"; 1729 } 1730 1731 if(!empty($new_stats)) 1732 { 1733 update_forum_counters($mergethread['fid'], $new_stats); 1734 update_forum_lastpost($mergethread['fid']); 1735 } 1736 } 1737 1738 if($thread['visible'] != $new_firstpost['visible']) 1739 { 1740 // Correct counters 1741 if($new_firstpost['visible'] == 1) 1742 { 1743 --$mergethread['replies']; 1744 } 1745 elseif($new_firstpost['visible'] == -1) 1746 { 1747 --$mergethread['deletedposts']; 1748 } 1749 else 1750 { 1751 --$mergethread['unapprovedposts']; 1752 } 1753 if($thread['visible'] == 1) 1754 { 1755 ++$mergethread['replies']; 1756 } 1757 elseif($thread['visible'] == -1) 1758 { 1759 ++$mergethread['deletedposts']; 1760 } 1761 else 1762 { 1763 ++$mergethread['unapprovedposts']; 1764 } 1765 } 1766 1767 // Update user counters 1768 foreach($user_posts as $uid => $counters) 1769 { 1770 $update_array = array( 1771 "postnum" => "+{$counters['postnum']}", 1772 "threadnum" => "+{$counters['threadnum']}", 1773 ); 1774 update_user_counters($uid, $update_array); 1775 } 1776 1777 $updated_stats = array( 1778 "replies" => "+{$mergethread['replies']}", 1779 "attachmentcount" => "+{$mergethread['attachmentcount']}", 1780 "unapprovedposts" => "+{$mergethread['unapprovedposts']}", 1781 "deletedposts" => "+{$mergethread['deletedposts']}" 1782 ); 1783 update_thread_counters($tid, $updated_stats); 1784 update_last_post($tid); 1785 1786 // Forum last post has to be updated after thread 1787 update_forum_lastpost($thread['fid']); 1788 return true; 1789 } 1790 1791 /** 1792 * Split posts into a new/existing thread 1793 * 1794 * @param array $pids PIDs of posts to split 1795 * @param int $tid Original thread ID (this is only used as a base for the new 1796 * thread; it can be set to 0 when the posts specified are coming from more 1797 * than 1 thread) 1798 * @param int $moveto Destination forum 1799 * @param string $newsubject New thread subject 1800 * @param int $destination_tid TID if moving into existing thread 1801 * @return int|bool New thread ID or false on failure 1802 */ 1803 function split_posts($pids, $tid, $moveto, $newsubject, $destination_tid=0) 1804 { 1805 global $db, $thread, $plugins, $cache; 1806 1807 $tid = (int)$tid; 1808 $moveto = (int)$moveto; 1809 $newtid = (int)$destination_tid; 1810 1811 // Make sure we only have valid values 1812 $pids = array_map('intval', $pids); 1813 1814 $pids_list = implode(',', $pids); 1815 1816 // Get forum infos 1817 $forum_cache = $cache->read('forums'); 1818 1819 if(empty($pids) || !$forum_cache[$moveto]) 1820 { 1821 return false; 1822 } 1823 1824 // Get the first split post 1825 $query = $db->simple_select('posts', 'pid,uid,visible,icon,username,dateline', 'pid IN ('.$pids_list.')', array('order_by' => 'dateline, pid', 'limit' => 1)); 1826 1827 $post_info = $db->fetch_array($query); 1828 1829 $visible = $post_info['visible']; 1830 1831 $forum_counters[$moveto] = array( 1832 'threads' => 0, 1833 'deletedthreads' => 0, 1834 'unapprovedthreads' => 0, 1835 'posts' => 0, 1836 'unapprovedposts' => 0, 1837 'deletedposts' => 0 1838 ); 1839 1840 $user_counters = array(); 1841 1842 if($destination_tid == 0) 1843 { 1844 // Splitting into a new thread 1845 // Create the new thread 1846 $newsubject = $db->escape_string($newsubject); 1847 $newthread = array( 1848 "fid" => $moveto, 1849 "subject" => $newsubject, 1850 "icon" => (int)$post_info['icon'], 1851 "uid" => (int)$post_info['uid'], 1852 "username" => $db->escape_string($post_info['username']), 1853 "dateline" => (int)$post_info['dateline'], 1854 "firstpost" => $post_info['pid'], 1855 "lastpost" => 0, 1856 "lastposter" => '', 1857 "visible" => (int)$visible, 1858 "notes" => '' 1859 ); 1860 $newtid = $db->insert_query("threads", $newthread); 1861 1862 if($visible == 1) 1863 { 1864 ++$forum_counters[$moveto]['threads']; 1865 if(!isset($user_counters[$newthread['uid']])) 1866 { 1867 $user_counters[$newthread['uid']] = array( 1868 'postnum' => 0, 1869 'threadnum' => 0 1870 ); 1871 } 1872 ++$user_counters[$newthread['uid']]['threadnum']; 1873 } 1874 elseif($visible == -1) 1875 { 1876 ++$forum_counters[$moveto]['deletedthreads']; 1877 } 1878 else 1879 { 1880 // Unapproved thread? 1881 ++$forum_counters[$moveto]['unapprovedthreads']; 1882 } 1883 } 1884 else 1885 { 1886 $newthread = get_thread($newtid); 1887 if(!$newthread) 1888 { 1889 return false; 1890 } 1891 $moveto = $newthread['fid']; 1892 } 1893 1894 // Get selected posts before moving forums to keep old fid 1895 $original_posts_query = $db->query(" 1896 SELECT p.pid, p.tid, p.fid, p.visible, p.uid, p.dateline, t.visible as threadvisible, t.firstpost, COUNT(a.aid) as postattachmentcount 1897 FROM ".TABLE_PREFIX."posts p 1898 LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid) 1899 LEFT JOIN ".TABLE_PREFIX."attachments a ON (a.pid=p.pid AND a.visible=1) 1900 WHERE p.pid IN ($pids_list) 1901 GROUP BY p.pid 1902 "); 1903 1904 // Move the selected posts over 1905 $sqlarray = array( 1906 "tid" => $newtid, 1907 "fid" => $moveto, 1908 "replyto" => 0 1909 ); 1910 $db->update_query("posts", $sqlarray, "pid IN ($pids_list)"); 1911 1912 $thread_counters[$newtid] = array( 1913 'replies' => 0, 1914 'unapprovedposts' => 0, 1915 'deletedposts' => 0, 1916 'attachmentcount' => 0 1917 ); 1918 1919 // Get posts being merged 1920 while($post = $db->fetch_array($original_posts_query)) 1921 { 1922 if(!isset($thread_counters[$post['tid']])) 1923 { 1924 $thread_counters[$post['tid']] = array( 1925 'replies' => 0, 1926 'unapprovedposts' => 0, 1927 'deletedposts' => 0, 1928 'attachmentcount' => 0 1929 ); 1930 } 1931 if(!isset($forum_counters[$post['fid']])) 1932 { 1933 $forum_counters[$post['fid']] = array( 1934 'posts' => 0, 1935 'unapprovedposts' => 0, 1936 'deletedposts' => 0 1937 ); 1938 } 1939 if(!isset($user_counters[$post['uid']])) 1940 { 1941 $user_counters[$post['uid']] = array( 1942 'postnum' => 0, 1943 'threadnum' => 0 1944 ); 1945 } 1946 if($post['visible'] == 1) 1947 { 1948 // Modify users' post counts 1949 if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1 && ($forum_cache[$moveto]['usepostcounts'] == 0 || $newthread['visible'] != 1)) 1950 { 1951 // Moving into a forum that doesn't count post counts 1952 --$user_counters[$post['uid']]['postnum']; 1953 } 1954 1955 // Subtract 1 from the old thread's replies 1956 --$thread_counters[$post['tid']]['replies']; 1957 } 1958 elseif($post['visible'] == 0) 1959 { 1960 // Unapproved post 1961 // Subtract 1 from the old thread's unapproved posts 1962 --$thread_counters[$post['tid']]['unapprovedposts']; 1963 } 1964 elseif($post['visible'] == -1) 1965 { 1966 // Soft deleted post 1967 // Subtract 1 from the old thread's deleted posts 1968 --$thread_counters[$post['tid']]['deletedposts']; 1969 } 1970 1971 // Subtract 1 from the old forum's posts 1972 if($post['threadvisible'] == 1 && $post['visible'] == 1) 1973 { 1974 --$forum_counters[$post['fid']]['posts']; 1975 } 1976 elseif($post['threadvisible'] == 0 || ($post['visible'] == 0 && $post['threadvisible'] == 1)) 1977 { 1978 --$forum_counters[$post['fid']]['unapprovedposts']; 1979 } 1980 else 1981 { 1982 --$forum_counters[$post['fid']]['deletedposts']; 1983 } 1984 1985 // Subtract attachment counts from old thread and add to new thread (which are counted regardless of post or attachment unapproval at time of coding) 1986 $thread_counters[$post['tid']]['attachmentcount'] -= $post['postattachmentcount']; 1987 $thread_counters[$newtid]['attachmentcount'] += $post['postattachmentcount']; 1988 1989 if($post['firstpost'] == $post['pid']) 1990 { 1991 // In some cases the first post of a thread changes 1992 // Therefore resync the visible field to make sure they're the same if they're not 1993 $query = $db->simple_select("posts", "pid, visible, uid", "tid='{$post['tid']}'", array('order_by' => 'dateline, pid', 'limit' => 1)); 1994 $new_firstpost = $db->fetch_array($query); 1995 1996 if(!isset($user_counters[$new_firstpost['uid']])) 1997 { 1998 $user_counters[$new_firstpost['uid']] = array( 1999 'postnum' => 0, 2000 'threadnum' => 0 2001 ); 2002 } 2003 2004 // Update post counters if visibility changes 2005 if($post['threadvisible'] != $new_firstpost['visible']) 2006 { 2007 $db->update_query("posts", array('visible' => $post['threadvisible']), "pid='{$new_firstpost['pid']}'"); 2008 // Subtract new first post 2009 if($new_firstpost['visible'] == 1) 2010 { 2011 --$thread_counters[$post['tid']]['replies']; 2012 if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1) 2013 { 2014 --$user_counters[$new_firstpost['uid']]['postnum']; 2015 } 2016 } 2017 elseif($new_firstpost['visible'] == -1) 2018 { 2019 --$thread_counters[$post['tid']]['deletedposts']; 2020 } 2021 else 2022 { 2023 --$thread_counters[$post['tid']]['unapprovedposts']; 2024 } 2025 if($post['threadvisible'] == 0 || ($new_firstpost['visible'] == 0 && $post['threadvisible'] == 1)) 2026 { 2027 --$forum_counters[$post['fid']]['unapprovedposts']; 2028 } 2029 else 2030 { 2031 --$forum_counters[$post['fid']]['deletedposts']; 2032 } 2033 2034 // Add old first post 2035 if($post['threadvisible'] == 1) 2036 { 2037 ++$thread_counters[$post['tid']]['replies']; 2038 ++$forum_counters[$post['fid']]['posts']; 2039 if($forum_cache[$post['fid']]['usepostcounts'] == 1) 2040 { 2041 ++$user_counters[$new_firstpost['uid']]['postnum']; 2042 } 2043 } 2044 elseif($post['threadvisible'] == -1) 2045 { 2046 ++$thread_counters[$post['tid']]['deletedposts']; 2047 ++$forum_counters[$post['fid']]['deletedposts']; 2048 } 2049 else 2050 { 2051 ++$thread_counters[$post['tid']]['unapprovedposts']; 2052 ++$forum_counters[$post['fid']]['unapprovedposts']; 2053 } 2054 } 2055 2056 // Update user thread counter if thread opener changes 2057 if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usethreadcounts'] == 1 && $post['uid'] != $new_firstpost['uid']) 2058 { 2059 // Subtract thread from old thread opener 2060 --$user_counters[$post['uid']]['threadnum']; 2061 // Add thread to new thread opener 2062 ++$user_counters[$new_firstpost['uid']]['threadnum']; 2063 } 2064 update_first_post($post['tid']); 2065 } 2066 2067 // This is the new first post of an existing thread? 2068 if($post['pid'] == $post_info['pid'] && $post['dateline'] < $newthread['dateline']) 2069 { 2070 // Update post counters if visibility changes 2071 if($post['visible'] != $newthread['visible']) 2072 { 2073 $db->update_query("posts", array('visible' => $newthread['visible']), "pid='{$post['pid']}'"); 2074 2075 // This is needed to update the forum counters correctly 2076 $post['visible'] = $newthread['visible']; 2077 } 2078 2079 // Update user thread counter if thread opener changes 2080 if($newthread['visible'] == 1 && $forum_cache[$newthread['fid']]['usethreadcounts'] == 1 && $post['uid'] != $newthread['uid']) 2081 { 2082 // Add thread to new thread opener 2083 ++$user_counters[$post['uid']]['threadnum']; 2084 if(!isset($user_counters[$newthread['uid']])) 2085 { 2086 $user_counters[$newthread['uid']] = array( 2087 'postnum' => 0, 2088 'threadnum' => 0 2089 ); 2090 } 2091 // Subtract thread from old thread opener 2092 --$user_counters[$newthread['uid']]['threadnum']; 2093 } 2094 update_first_post($newtid); 2095 } 2096 2097 if($post['visible'] == 1) 2098 { 2099 // Modify users' post counts 2100 if($newthread['visible'] == 1 && ($forum_cache[$post['fid']]['usepostcounts'] == 0 || $post['threadvisible'] != 1) && $forum_cache[$moveto]['usepostcounts'] == 1) 2101 { 2102 // Moving into a forum that does count post counts 2103 ++$user_counters[$post['uid']]['postnum']; 2104 } 2105 2106 // Add 1 to the new thread's replies 2107 ++$thread_counters[$newtid]['replies']; 2108 } 2109 elseif($post['visible'] == 0) 2110 { 2111 // Unapproved post 2112 // Add 1 to the new thread's unapproved posts 2113 ++$thread_counters[$newtid]['unapprovedposts']; 2114 } 2115 elseif($post['visible'] == -1) 2116 { 2117 // Soft deleted post 2118 // Add 1 to the new thread's deleted posts 2119 ++$thread_counters[$newtid]['deletedposts']; 2120 } 2121 2122 // Add 1 to the new forum's posts 2123 if($newthread['visible'] == 1 && $post['visible'] == 1) 2124 { 2125 ++$forum_counters[$moveto]['posts']; 2126 } 2127 elseif($newthread['visible'] == 0 || ($post['visible'] == 0 && $newthread['visible'] == 1)) 2128 { 2129 ++$forum_counters[$moveto]['unapprovedposts']; 2130 } 2131 else 2132 { 2133 ++$forum_counters[$moveto]['deletedposts']; 2134 } 2135 } 2136 2137 // Attach moved posts to the first post 2138 $db->update_query("posts", array('replyto' => $post_info['pid']), "tid='{$newtid}' AND replyto = 0 AND pid != '{$post_info['pid']}'"); 2139 2140 if($destination_tid == 0 && $newthread['visible'] == 1) 2141 { 2142 // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post 2143 --$thread_counters[$newtid]['replies']; 2144 } 2145 elseif($destination_tid == 0 && $newthread['visible'] == 0) 2146 { 2147 // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post 2148 --$thread_counters[$newtid]['unapprovedposts']; 2149 } 2150 elseif($destination_tid == 0 && $newthread['visible'] == -1) 2151 { 2152 // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post 2153 --$thread_counters[$newtid]['deletedposts']; 2154 } 2155 2156 $arguments = array("pids" => $pids, "tid" => $tid, "moveto" => $moveto, "newsubject" => $newsubject, "destination_tid" => $destination_tid); 2157 $plugins->run_hooks("class_moderation_split_posts", $arguments); 2158 2159 // Update user post counts 2160 if(!empty($user_counters)) 2161 { 2162 foreach($user_counters as $uid => $counters) 2163 { 2164 foreach($counters as $key => $counter) 2165 { 2166 if($counter >= 0) 2167 { 2168 $counters[$key] = "+{$counter}"; // add the addition operator for query 2169 } 2170 } 2171 update_user_counters($uid, $counters); 2172 } 2173 } 2174 2175 // Update thread counters 2176 if(is_array($thread_counters)) 2177 { 2178 foreach($thread_counters as $tid => $counters) 2179 { 2180 if($tid == $newtid) 2181 { 2182 // Update the subject of the first post in the new thread 2183 $query = $db->simple_select("posts", "pid", "tid='$newtid'", array('order_by' => 'dateline, pid', 'limit' => 1)); 2184 $newthread = $db->fetch_array($query); 2185 $sqlarray = array( 2186 "subject" => $newsubject, 2187 "replyto" => 0 2188 ); 2189 $db->update_query("posts", $sqlarray, "pid='{$newthread['pid']}'"); 2190 } 2191 else 2192 { 2193 // Update the subject of the first post in the old thread 2194 $query = $db->query(" 2195 SELECT p.pid, t.subject 2196 FROM ".TABLE_PREFIX."posts p 2197 LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid) 2198 WHERE p.tid='{$tid}' 2199 ORDER BY p.dateline ASC, p.pid ASC 2200 LIMIT 1 2201 "); 2202 $oldthread = $db->fetch_array($query); 2203 $sqlarray = array( 2204 "subject" => $db->escape_string($oldthread['subject']), 2205 "replyto" => 0 2206 ); 2207 $db->update_query("posts", $sqlarray, "pid='{$oldthread['pid']}'"); 2208 } 2209 2210 foreach($counters as $key => $counter) 2211 { 2212 if($counter >= 0) 2213 { 2214 $counters[$key] = "+{$counter}"; 2215 } 2216 } 2217 update_thread_counters($tid, $counters); 2218 update_last_post($tid); 2219 } 2220 } 2221 2222 // Update forum counters 2223 if(!empty($forum_counters)) 2224 { 2225 foreach($forum_counters as $fid => $counters) 2226 { 2227 foreach($counters as $key => $counter) 2228 { 2229 if($counter >= 0) 2230 { 2231 $counters[$key] = "+{$counter}"; 2232 } 2233 } 2234 update_forum_counters($fid, $counters); 2235 update_forum_lastpost($fid); 2236 } 2237 } 2238 2239 return $newtid; 2240 } 2241 2242 /** 2243 * Move multiple threads to new forum 2244 * 2245 * @param array $tids Thread IDs 2246 * @param int $moveto Destination forum 2247 * @return boolean 2248 * 2249 * @deprecated Iterate over move_thread instead 2250 */ 2251 function move_threads($tids, $moveto) 2252 { 2253 global $db, $plugins; 2254 2255 // Make sure we only have valid values 2256 $tids = array_map('intval', $tids); 2257 2258 $tid_list = implode(',', $tids); 2259 2260 $moveto = (int)$moveto; 2261 2262 $newforum = get_forum($moveto); 2263 2264 if(empty($tids) || !$newforum) 2265 { 2266 return false; 2267 } 2268 2269 $total_posts = $total_unapproved_posts = $total_deleted_posts = $total_threads = $total_unapproved_threads = $total_deleted_threads = 0; 2270 $forum_counters = $user_counters = array(); 2271 $query = $db->simple_select("threads", "fid, visible, replies, unapprovedposts, deletedposts, tid, uid", "tid IN ($tid_list)"); 2272 while($thread = $db->fetch_array($query)) 2273 { 2274 $forum = get_forum($thread['fid']); 2275 2276 if(!isset($forum_counters[$thread['fid']])) 2277 { 2278 $forum_counters[$thread['fid']] = array( 2279 'posts' => 0, 2280 'threads' => 0, 2281 'unapprovedposts' => 0, 2282 'unapprovedthreads' => 0, 2283 'deletedthreads' => 0, 2284 'deletedposts' => 0 2285 ); 2286 } 2287 2288 if(!isset($user_counters[$thread['uid']])) 2289 { 2290 $user_counters[$thread['uid']] = array( 2291 'num_posts' => 0, 2292 'num_threads' => 0 2293 ); 2294 } 2295 2296 if($thread['visible'] == 1) 2297 { 2298 $total_posts += $thread['replies']+1; 2299 $total_unapproved_posts += $thread['unapprovedposts']; 2300 $total_deleted_posts += $thread['deletedposts']; 2301 $forum_counters[$thread['fid']]['posts'] += $thread['replies']+1; 2302 $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['unapprovedposts']; 2303 $forum_counters[$thread['fid']]['deletedposts'] += $thread['deletedposts']; 2304 2305 $forum_counters[$thread['fid']]['threads']++; 2306 ++$total_threads; 2307 2308 if($newforum['usethreadcounts'] == 1 && $forum['usethreadcounts'] == 0) 2309 { 2310 ++$user_counters[$thread['uid']]['num_threads']; 2311 } 2312 else if($newforum['usethreadcounts'] == 0 && $forum['usethreadcounts'] == 1) 2313 { 2314 --$user_counters[$thread['uid']]['num_threads']; 2315 } 2316 2317 $query1 = $db->query(" 2318 SELECT COUNT(p.pid) AS posts, u.uid 2319 FROM ".TABLE_PREFIX."posts p 2320 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) 2321 WHERE p.tid = '{$thread['tid']}' AND p.visible=1 2322 GROUP BY u.uid 2323 ORDER BY posts DESC 2324 "); 2325 while($posters = $db->fetch_array($query1)) 2326 { 2327 if(!isset($user_counters[$posters['uid']])) 2328 { 2329 $user_counters[$posters['uid']] = array( 2330 'num_posts' => 0, 2331 'num_threads' => 0 2332 ); 2333 } 2334 2335 if($newforum['usepostcounts'] != 0 && $forum['usepostcounts'] == 0) 2336 { 2337 $user_counters[$posters['uid']]['num_posts'] += $posters['posts']; 2338 } 2339 else if($newforum['usepostcounts'] == 0 && $forum['usepostcounts'] != 0) 2340 { 2341 $user_counters[$posters['uid']]['num_posts'] -= $posters['posts']; 2342 } 2343 } 2344 } 2345 elseif($thread['visible'] == -1) 2346 { 2347 $total_deleted_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; 2348 2349 $forum_counters[$thread['fid']]['deletedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied deleted posts counter for deleted threads 2350 2351 $forum_counters[$thread['fid']]['deletedthreads']++; 2352 ++$total_deleted_threads; 2353 } 2354 else 2355 { 2356 $total_unapproved_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; 2357 2358 $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied unapproved posts counter for unapproved threads 2359 2360 $forum_counters[$thread['fid']]['unapprovedthreads']++; 2361 ++$total_unapproved_threads; 2362 } 2363 2364 // Remove old redirects 2365 $redirects_query = $db->simple_select('threads', 'tid', "closed='moved|{$thread['tid']}' AND fid='$moveto'"); 2366 while($redirect_tid = $db->fetch_field($redirects_query, 'tid')) 2367 { 2368 $this->delete_thread($redirect_tid); 2369 } 2370 } 2371 2372 $sqlarray = array( 2373 "fid" => $moveto, 2374 ); 2375 $db->update_query("threads", $sqlarray, "tid IN ($tid_list)"); 2376 $db->update_query("posts", $sqlarray, "tid IN ($tid_list)"); 2377 2378 // If any of the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix 2379 $query = $db->simple_select("threads", "tid, prefix", "tid IN ($tid_list) AND prefix != 0"); 2380 while($thread = $db->fetch_array($query)) 2381 { 2382 switch($db->type) 2383 { 2384 case "pgsql": 2385 case "sqlite": 2386 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 2387 break; 2388 default: 2389 $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'"); 2390 } 2391 if($db->fetch_field($query, "num_prefixes") == 0) 2392 { 2393 $sqlarray = array( 2394 "prefix" => 0, 2395 ); 2396 $db->update_query("threads", $sqlarray, "tid = '{$thread['tid']}'"); 2397 } 2398 } 2399 2400 $arguments = array("tids" => $tids, "moveto" => $moveto); 2401 $plugins->run_hooks("class_moderation_move_threads", $arguments); 2402 2403 if(!empty($user_counters)) 2404 { 2405 foreach($user_counters as $uid => $counters) 2406 { 2407 $update_array = array( 2408 "postnum" => "+{$counters['num_posts']}", 2409 "threadnum" => "+{$counters['num_threads']}", 2410 ); 2411 update_user_counters($uid, $update_array); 2412 } 2413 } 2414 2415 if(is_array($forum_counters)) 2416 { 2417 foreach($forum_counters as $fid => $counter) 2418 { 2419 $updated_count = array( 2420 'posts' => "-{$counter['posts']}", 2421 'threads' => "-{$counter['threads']}", 2422 'unapprovedposts' => "-{$counter['unapprovedposts']}", 2423 'unapprovedthreads' => "-{$counter['unapprovedthreads']}", 2424 'deletedposts' => "-{$counter['deletedposts']}", 2425 'deletedthreads' => "-{$counter['deletedthreads']}" 2426 2427 ); 2428 update_forum_counters($fid, $updated_count); 2429 update_forum_lastpost($fid); 2430 } 2431 } 2432 2433 $updated_count = array( 2434 "threads" => "+{$total_threads}", 2435 "unapprovedthreads" => "+{$total_unapproved_threads}", 2436 "posts" => "+{$total_posts}", 2437 "unapprovedposts" => "+{$total_unapproved_posts}", 2438 'deletedposts' => "+{$total_deleted_posts}", 2439 "deletedthreads" => "+{$total_deleted_threads}" 2440 ); 2441 2442 update_forum_counters($moveto, $updated_count); 2443 update_forum_lastpost($moveto); 2444 2445 // Remove thread subscriptions for the users who no longer have permission to view the thread 2446 $this->remove_thread_subscriptions($tid_list, false, $moveto); 2447 2448 return true; 2449 } 2450 2451 /** 2452 * Approve multiple posts 2453 * 2454 * @param array $pids PIDs 2455 * @return boolean 2456 */ 2457 function approve_posts($pids) 2458 { 2459 global $db, $cache, $plugins; 2460 2461 $num_posts = 0; 2462 2463 if(empty($pids)) 2464 { 2465 return false; 2466 } 2467 2468 // Make sure we only have valid values 2469 $pids = array_map('intval', $pids); 2470 2471 $pid_list = implode(',', $pids); 2472 $pids = $threads_to_update = array(); 2473 2474 // Make visible 2475 $approve = array( 2476 "visible" => 1, 2477 ); 2478 2479 // We have three cases we deal with in these code segments: 2480 // 1) We're approving specific unapproved posts 2481 // 1.1) if the thread is approved 2482 // 1.2) if the thread is unapproved 2483 // 2) We're approving the firstpost of the thread, therefore approving the thread itself 2484 // 3) We're doing both 1 and 2 2485 $query = $db->query(" 2486 SELECT p.tid 2487 FROM ".TABLE_PREFIX."posts p 2488 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 2489 WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost = p.pid AND t.visible = 0 2490 "); 2491 while($post = $db->fetch_array($query)) 2492 { 2493 // This is the first post in the thread so we're approving the whole thread. 2494 $threads_to_update[] = $post['tid']; 2495 } 2496 2497 if(!empty($threads_to_update)) 2498 { 2499 $this->approve_threads($threads_to_update); 2500 } 2501 2502 $thread_counters = $forum_counters = $user_counters = array(); 2503 2504 $query = $db->query(" 2505 SELECT p.pid, p.tid, p.fid, p.uid, t.visible AS threadvisible 2506 FROM ".TABLE_PREFIX."posts p 2507 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 2508 WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost != p.pid 2509 "); 2510 while($post = $db->fetch_array($query)) 2511 { 2512 $pids[] = $post['pid']; 2513 2514 if(!isset($thread_counters[$post['tid']])) 2515 { 2516 $thread_counters[$post['tid']] = array( 2517 'replies' => 0 2518 ); 2519 } 2520 2521 ++$thread_counters[$post['tid']]['replies']; 2522 2523 // If the thread of this post is unapproved then we've already taken into account this counter as implied. 2524 // Updating it again would cause it to double count 2525 if($post['threadvisible'] == 1) 2526 { 2527 if(!isset($forum_counters[$post['fid']])) 2528 { 2529 $forum_counters[$post['fid']] = array( 2530 'num_posts' => 0 2531 ); 2532 } 2533 ++$forum_counters[$post['fid']]['num_posts']; 2534 } 2535 2536 $forum = get_forum($post['fid']); 2537 2538 // If post counts enabled in this forum and the thread is approved, add 1 2539 if($forum['usepostcounts'] != 0 && $post['threadvisible'] == 1) 2540 { 2541 if(!isset($user_counters[$post['uid']])) 2542 { 2543 $user_counters[$post['uid']] = 0; 2544 } 2545 ++$user_counters[$post['uid']]; 2546 } 2547 } 2548 2549 if(empty($pids) && empty($threads_to_update)) 2550 { 2551 return false; 2552 } 2553 2554 if(!empty($pids)) 2555 { 2556 $where = "pid IN (".implode(',', $pids).")"; 2557 $db->update_query("posts", $approve, $where); 2558 } 2559 2560 $plugins->run_hooks("class_moderation_approve_posts", $pids); 2561 2562 if(!empty($thread_counters)) 2563 { 2564 foreach($thread_counters as $tid => $counters) 2565 { 2566 $counters_update = array( 2567 "unapprovedposts" => "-".$counters['replies'], 2568 "replies" => "+".$counters['replies'] 2569 ); 2570 update_thread_counters($tid, $counters_update); 2571 update_last_post($tid); 2572 } 2573 } 2574 2575 if(!empty($forum_counters)) 2576 { 2577 foreach($forum_counters as $fid => $counters) 2578 { 2579 $updated_forum_stats = array( 2580 'posts' => "+{$counters['num_posts']}", 2581 'unapprovedposts' => "-{$counters['num_posts']}", 2582 ); 2583 update_forum_counters($fid, $updated_forum_stats); 2584 update_forum_lastpost($fid); 2585 } 2586 } 2587 2588 if(!empty($user_counters)) 2589 { 2590 foreach($user_counters as $uid => $counter) 2591 { 2592 update_user_counters($uid, array('postnum' => "+{$counter}")); 2593 } 2594 } 2595 2596 return true; 2597 } 2598 2599 /** 2600 * Unapprove multiple posts 2601 * 2602 * @param array $pids PIDs 2603 * @return boolean 2604 */ 2605 function unapprove_posts($pids) 2606 { 2607 global $db, $cache, $plugins; 2608 2609 if(empty($pids)) 2610 { 2611 return false; 2612 } 2613 2614 // Make sure we only have valid values 2615 $pids = array_map('intval', $pids); 2616 2617 $pid_list = implode(',', $pids); 2618 $pids = $threads_to_update = array(); 2619 2620 // Make invisible 2621 $approve = array( 2622 "visible" => 0, 2623 ); 2624 2625 // We have three cases we deal with in these code segments: 2626 // 1) We're unapproving specific approved posts 2627 // 1.1) if the thread is approved 2628 // 1.2) if the thread is unapproved 2629 // 1.3) if the thread is deleted 2630 // 2) We're unapproving the firstpost of the thread, therefore unapproving the thread itself 2631 // 3) We're doing both 1 and 2 2632 $query = $db->query(" 2633 SELECT p.tid 2634 FROM ".TABLE_PREFIX."posts p 2635 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 2636 WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost = p.pid AND t.visible IN (-1,1) 2637 "); 2638 while($post = $db->fetch_array($query)) 2639 { 2640 // This is the first post in the thread so we're unapproving the whole thread. 2641 $threads_to_update[] = $post['tid']; 2642 } 2643 2644 if(!empty($threads_to_update)) 2645 { 2646 $this->unapprove_threads($threads_to_update); 2647 } 2648 2649 $thread_counters = $forum_counters = $user_counters = array(); 2650 2651 $query = $db->query(" 2652 SELECT p.pid, p.tid, p.visible, p.fid, p.uid, t.visible AS threadvisible 2653 FROM ".TABLE_PREFIX."posts p 2654 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 2655 WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost != p.pid 2656 "); 2657 while($post = $db->fetch_array($query)) 2658 { 2659 $pids[] = $post['pid']; 2660 2661 if(!isset($thread_counters[$post['tid']])) 2662 { 2663 $thread_counters[$post['tid']] = array( 2664 'replies' => 0, 2665 'unapprovedposts' => 0, 2666 'deletedposts' => 0 2667 ); 2668 } 2669 2670 ++$thread_counters[$post['tid']]['unapprovedposts']; 2671 if($post['visible'] == 1) 2672 { 2673 ++$thread_counters[$post['tid']]['replies']; 2674 } 2675 else 2676 { 2677 ++$thread_counters[$post['tid']]['deletedposts']; 2678 } 2679 2680 if(!isset($forum_counters[$post['fid']])) 2681 { 2682 $forum_counters[$post['fid']] = array( 2683 'num_posts' => 0, 2684 'num_unapproved_posts' => 0, 2685 'num_deleted_posts' => 0 2686 ); 2687 } 2688 2689 // If the thread of this post is unapproved then we've already taken into account this counter as implied. 2690 // Updating it again would cause it to double count 2691 if($post['threadvisible'] != 0) 2692 { 2693 ++$forum_counters[$post['fid']]['num_unapproved_posts']; 2694 if($post['visible'] == 1) 2695 { 2696 ++$forum_counters[$post['fid']]['num_posts']; 2697 } 2698 else 2699 { 2700 ++$forum_counters[$post['fid']]['num_deleted_posts']; 2701 } 2702 } 2703 2704 $forum = get_forum($post['fid']); 2705 2706 // If post counts enabled in this forum and the thread is approved, subtract 1 2707 if($forum['usepostcounts'] != 0 && $post['visible'] == 1 && $post['threadvisible'] == 1) 2708 { 2709 if(!isset($user_counters[$post['uid']])) 2710 { 2711 $user_counters[$post['uid']] = 0; 2712 } 2713 --$user_counters[$post['uid']]; 2714 } 2715 } 2716 2717 if(empty($pids) && empty($threads_to_update)) 2718 { 2719 return false; 2720 } 2721 2722 if(!empty($pids)) 2723 { 2724 $where = "pid IN (".implode(',', $pids).")"; 2725 $db->update_query("posts", $approve, $where); 2726 } 2727 2728 $plugins->run_hooks("class_moderation_unapprove_posts", $pids); 2729 2730 if(!empty($thread_counters)) 2731 { 2732 foreach($thread_counters as $tid => $counters) 2733 { 2734 $counters_update = array( 2735 "unapprovedposts" => "+".$counters['unapprovedposts'], 2736 "replies" => "-".$counters['replies'], 2737 "deletedposts" => "-".$counters['deletedposts'] 2738 ); 2739 2740 update_thread_counters($tid, $counters_update); 2741 update_last_post($tid); 2742 } 2743 } 2744 2745 if(!empty($forum_counters)) 2746 { 2747 foreach($forum_counters as $fid => $counters) 2748 { 2749 $updated_forum_stats = array( 2750 'posts' => "-{$counters['num_posts']}", 2751 'unapprovedposts' => "+{$counters['num_unapproved_posts']}", 2752 'deletedposts' => "-{$counters['num_deleted_posts']}" 2753 ); 2754 update_forum_counters($fid, $updated_forum_stats); 2755 update_forum_lastpost($fid); 2756 } 2757 } 2758 2759 if(!empty($user_counters)) 2760 { 2761 foreach($user_counters as $uid => $counter) 2762 { 2763 update_user_counters($uid, array('postnum' => "{$counter}")); 2764 } 2765 } 2766 2767 return true; 2768 } 2769 2770 /** 2771 * Change thread subject 2772 * 2773 * @param int|array $tids Thread ID(s) 2774 * @param string $format Format of new subject (with {subject}) 2775 * @return boolean 2776 */ 2777 function change_thread_subject($tids, $format) 2778 { 2779 global $db, $mybb, $plugins; 2780 2781 // Get tids into list 2782 if(!is_array($tids)) 2783 { 2784 $tids = array($tids); 2785 } 2786 2787 // Make sure we only have valid values 2788 $tids = array_map('intval', $tids); 2789 2790 if(empty($tids)) 2791 { 2792 return false; 2793 } 2794 2795 $tid_list = implode(',', $tids); 2796 2797 // Get original subject 2798 $query = $db->query(" 2799 SELECT u.uid, u.username, t.tid, t.subject FROM ".TABLE_PREFIX."threads t 2800 LEFT JOIN ".TABLE_PREFIX."users u ON t.uid=u.uid 2801 WHERE tid IN ($tid_list) 2802 "); 2803 while($thread = $db->fetch_array($query)) 2804 { 2805 // Update threads and first posts with new subject 2806 $find = array('{username}', 'author', '{subject}'); 2807 $replace = array($mybb->user['username'], $thread['username'], $thread['subject']); 2808 2809 $new_subject = str_ireplace($find, $replace, $format); 2810 2811 $args = array( 2812 'thread' => &$thread, 2813 'new_subject' => &$new_subject, 2814 ); 2815 2816 $plugins->run_hooks("class_moderation_change_thread_subject_newsubject", $args); 2817 2818 $update_subject = array( 2819 "subject" => $db->escape_string($new_subject) 2820 ); 2821 $db->update_query("threads", $update_subject, "tid='{$thread['tid']}'"); 2822 $db->update_query("posts", $update_subject, "tid='{$thread['tid']}' AND replyto='0'"); 2823 } 2824 2825 $arguments = array("tids" => $tids, "format" => $format); 2826 $plugins->run_hooks("class_moderation_change_thread_subject", $arguments); 2827 2828 return true; 2829 } 2830 2831 /** 2832 * Add thread expiry 2833 * 2834 * @param int $tid Thread ID 2835 * @param int $deletetime Timestamp when the thread is deleted 2836 * @return boolean 2837 */ 2838 function expire_thread($tid, $deletetime) 2839 { 2840 global $db, $plugins; 2841 2842 $tid = (int)$tid; 2843 2844 if(empty($tid)) 2845 { 2846 return false; 2847 } 2848 2849 $update_thread = array( 2850 "deletetime" => (int)$deletetime 2851 ); 2852 $db->update_query("threads", $update_thread, "tid='{$tid}'"); 2853 2854 $arguments = array("tid" => $tid, "deletetime" => $deletetime); 2855 $plugins->run_hooks("class_moderation_expire_thread", $arguments); 2856 2857 return true; 2858 } 2859 2860 /** 2861 * Toggle post visibility (approved/unapproved) 2862 * 2863 * @param array $pids Post IDs 2864 * @return boolean true 2865 */ 2866 function toggle_post_visibility($pids) 2867 { 2868 global $db; 2869 2870 // Make sure we only have valid values 2871 $pids = array_map('intval', $pids); 2872 2873 $pid_list = implode(',', $pids); 2874 $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)"); 2875 while($post = $db->fetch_array($query)) 2876 { 2877 if($post['visible'] != 0) 2878 { 2879 $unapprove[] = $post['pid']; 2880 } 2881 else 2882 { 2883 $approve[] = $post['pid']; 2884 } 2885 } 2886 if(is_array($unapprove)) 2887 { 2888 $this->unapprove_posts($unapprove); 2889 } 2890 if(is_array($approve)) 2891 { 2892 $this->approve_posts($approve); 2893 } 2894 return true; 2895 } 2896 2897 /** 2898 * Toggle post visibility (deleted/restored) 2899 * 2900 * @param array $pids Post IDs 2901 * @return boolean true 2902 */ 2903 function toggle_post_softdelete($pids) 2904 { 2905 global $db; 2906 2907 // Make sure we only have valid values 2908 $pids = array_map('intval', $pids); 2909 2910 $pid_list = implode(',', $pids); 2911 $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)"); 2912 while($post = $db->fetch_array($query)) 2913 { 2914 if($post['visible'] != -1) 2915 { 2916 $delete[] = $post['pid']; 2917 } 2918 else 2919 { 2920 $restore[] = $post['pid']; 2921 } 2922 } 2923 if(is_array($delete)) 2924 { 2925 $this->soft_delete_posts($delete); 2926 } 2927 if(is_array($restore)) 2928 { 2929 $this->restore_posts($restore); 2930 } 2931 return true; 2932 } 2933 2934 /** 2935 * Toggle thread visibility (approved/unapproved) 2936 * 2937 * @param array $tids Thread IDs 2938 * @param int $fid Forum ID 2939 * @return boolean true 2940 */ 2941 function toggle_thread_visibility($tids, $fid) 2942 { 2943 global $db; 2944 2945 // Make sure we only have valid values 2946 $tids = array_map('intval', $tids); 2947 $fid = (int)$fid; 2948 2949 $tid_list = implode(',', $tids); 2950 $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)"); 2951 while($thread = $db->fetch_array($query)) 2952 { 2953 if($thread['visible'] != 0) 2954 { 2955 $unapprove[] = $thread['tid']; 2956 } 2957 else 2958 { 2959 $approve[] = $thread['tid']; 2960 } 2961 } 2962 if(is_array($unapprove)) 2963 { 2964 $this->unapprove_threads($unapprove, $fid); 2965 } 2966 if(is_array($approve)) 2967 { 2968 $this->approve_threads($approve, $fid); 2969 } 2970 return true; 2971 } 2972 2973 /** 2974 * Toggle thread visibility (deleted/restored) 2975 * 2976 * @param array $tids Thread IDs 2977 * @return boolean true 2978 */ 2979 function toggle_thread_softdelete($tids) 2980 { 2981 global $db; 2982 2983 // Make sure we only have valid values 2984 $tids = array_map('intval', $tids); 2985 2986 $tid_list = implode(',', $tids); 2987 $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)"); 2988 while($thread = $db->fetch_array($query)) 2989 { 2990 if($thread['visible'] != -1) 2991 { 2992 $delete[] = $thread['tid']; 2993 } 2994 else 2995 { 2996 $restore[] = $thread['tid']; 2997 } 2998 } 2999 if(is_array($delete)) 3000 { 3001 $this->soft_delete_threads($delete); 3002 } 3003 if(is_array($restore)) 3004 { 3005 $this->restore_threads($restore); 3006 } 3007 return true; 3008 } 3009 3010 /** 3011 * Toggle threads open/closed 3012 * 3013 * @param array $tids Thread IDs 3014 * @return boolean true 3015 */ 3016 function toggle_thread_status($tids) 3017 { 3018 global $db; 3019 3020 // Make sure we only have valid values 3021 $tids = array_map('intval', $tids); 3022 3023 $tid_list = implode(',', $tids); 3024 $query = $db->simple_select("threads", 'tid, closed', "tid IN ($tid_list)"); 3025 while($thread = $db->fetch_array($query)) 3026 { 3027 if($thread['closed'] == 1) 3028 { 3029 $open[] = $thread['tid']; 3030 } 3031 elseif($thread['closed'] == 0) 3032 { 3033 $close[] = $thread['tid']; 3034 } 3035 } 3036 if(is_array($open)) 3037 { 3038 $this->open_threads($open); 3039 } 3040 if(is_array($close)) 3041 { 3042 $this->close_threads($close); 3043 } 3044 return true; 3045 } 3046 3047 /** 3048 * Toggle threads stick/unstick 3049 * 3050 * @param array $tids Thread IDs 3051 * @return boolean true 3052 */ 3053 function toggle_thread_importance($tids) 3054 { 3055 global $db; 3056 3057 // Make sure we only have valid values 3058 $tids = array_map('intval', $tids); 3059 3060 $stick = array(); 3061 $unstick = array(); 3062 3063 $tid_list = implode(',', $tids); 3064 $query = $db->simple_select("threads", 'tid, sticky', "tid IN ($tid_list)"); 3065 while($thread = $db->fetch_array($query)) 3066 { 3067 if($thread['sticky'] == 0) 3068 { 3069 $stick[] = $thread['tid']; 3070 } 3071 elseif($thread['sticky'] == 1) 3072 { 3073 $unstick[] = $thread['tid']; 3074 } 3075 } 3076 if(!empty($stick)) 3077 { 3078 $this->stick_threads($stick); 3079 } 3080 if(!empty($unstick)) 3081 { 3082 $this->unstick_threads($unstick); 3083 } 3084 return true; 3085 } 3086 3087 /** 3088 * Remove thread subscriptions (from one or multiple threads in the same forum) 3089 * 3090 * @param int|array $tids Thread ID, or an array of thread IDs from the same forum. 3091 * @param boolean $all True (default) to delete all subscriptions, false to only delete subscriptions from users with no permission to read the thread 3092 * @param int $fid (Only applies if $all is false) The forum ID of the thread 3093 * @return boolean 3094 */ 3095 function remove_thread_subscriptions($tids, $all = true, $fid = 0) 3096 { 3097 global $db, $plugins; 3098 3099 // Format thread IDs 3100 if(!is_array($tids)) 3101 { 3102 $tids = array($tids); 3103 } 3104 3105 if(empty($tids)) 3106 { 3107 return false; 3108 } 3109 3110 // Make sure we only have valid values 3111 $tids = array_map('intval', $tids); 3112 $fid = (int)$fid; 3113 3114 $tids_csv = implode(',', $tids); 3115 3116 // Delete only subscriptions from users who no longer have permission to read the thread. 3117 if(!$all) 3118 { 3119 // Get groups that cannot view the forum or its threads 3120 $forum_parentlist = get_parent_list($fid); 3121 $query = $db->simple_select("forumpermissions", "gid", "fid IN ({$forum_parentlist}) AND (canview=0 OR canviewthreads=0)"); 3122 $groups = array(); 3123 $additional_groups = ''; 3124 while($group = $db->fetch_array($query)) 3125 { 3126 $groups[] = $group['gid']; 3127 switch($db->type) 3128 { 3129 case "pgsql": 3130 case "sqlite": 3131 $additional_groups .= " OR ','||u.additionalgroups||',' LIKE ',{$group['gid']},'"; 3132 break; 3133 default: 3134 $additional_groups .= " OR CONCAT(',',u.additionalgroups,',') LIKE ',{$group['gid']},'"; 3135 } 3136 } 3137 // If there are groups found, delete subscriptions from users in these groups 3138 if(count($groups) > 0) 3139 { 3140 $groups_csv = implode(',', $groups); 3141 $query = $db->query(" 3142 SELECT s.tid, u.uid 3143 FROM ".TABLE_PREFIX."threadsubscriptions s 3144 LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=s.uid) 3145 WHERE s.tid IN ({$tids_csv}) 3146 AND (u.usergroup IN ({$groups_csv}){$additional_groups}) 3147 "); 3148 while($subscription = $db->fetch_array($query)) 3149 { 3150 $db->delete_query("threadsubscriptions", "uid='{$subscription['uid']}' AND tid='{$subscription['tid']}'"); 3151 } 3152 } 3153 } 3154 // Delete all subscriptions of this thread 3155 else 3156 { 3157 $db->delete_query("threadsubscriptions", "tid IN ({$tids_csv})"); 3158 } 3159 3160 $arguments = array("tids" => $tids, "all" => $all, "fid" => $fid); 3161 $plugins->run_hooks("class_moderation_remove_thread_subscriptions", $arguments); 3162 3163 return true; 3164 } 3165 3166 /** 3167 * Apply a thread prefix (to one or multiple threads in the same forum) 3168 * 3169 * @param int|array $tids Thread ID, or an array of thread IDs from the same forum. 3170 * @param int $prefix Prefix ID to apply to the threads 3171 * @return bool 3172 */ 3173 function apply_thread_prefix($tids, $prefix = 0) 3174 { 3175 global $db, $plugins; 3176 3177 // Format thread IDs 3178 if(!is_array($tids)) 3179 { 3180 $tids = array($tids); 3181 } 3182 3183 if(empty($tids)) 3184 { 3185 return false; 3186 } 3187 3188 // Make sure we only have valid values 3189 $tids = array_map('intval', $tids); 3190 $tids_csv = implode(',', $tids); 3191 3192 $update_thread = array('prefix' => (int)$prefix); 3193 $db->update_query('threads', $update_thread, "tid IN ({$tids_csv})"); 3194 3195 $arguments = array('tids' => $tids, 'prefix' => $prefix); 3196 3197 $plugins->run_hooks('class_moderation_apply_thread_prefix', $arguments); 3198 3199 return true; 3200 } 3201 3202 /** 3203 * Soft delete multiple posts 3204 * 3205 * @param array $pids PIDs 3206 * @return boolean 3207 */ 3208 function soft_delete_posts($pids) 3209 { 3210 global $db, $cache, $plugins; 3211 3212 if(empty($pids)) 3213 { 3214 return false; 3215 } 3216 3217 // Make sure we only have valid values 3218 $pids = array_map('intval', $pids); 3219 3220 $pid_list = implode(',', $pids); 3221 $pids = $threads_to_update = array(); 3222 3223 // Make invisible 3224 $update = array( 3225 "visible" => -1, 3226 ); 3227 3228 // We have three cases we deal with in these code segments: 3229 // 1) We're deleting specific approved posts 3230 // 1.1) if the thread is approved 3231 // 1.2) if the thread is unapproved 3232 // 1.3) if the thread is deleted 3233 // 2) We're deleting the firstpost of the thread, therefore deleting the thread itself 3234 // 3) We're doing both 1 and 2 3235 $query = $db->query(" 3236 SELECT p.tid 3237 FROM ".TABLE_PREFIX."posts p 3238 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 3239 WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost = p.pid AND t.visible IN (0,1) 3240 "); 3241 while($post = $db->fetch_array($query)) 3242 { 3243 // This is the first post in the thread so we're deleting the whole thread. 3244 $threads_to_update[] = $post['tid']; 3245 } 3246 3247 if(!empty($threads_to_update)) 3248 { 3249 $this->soft_delete_threads($threads_to_update); 3250 } 3251 3252 $thread_counters = $forum_counters = $user_counters = array(); 3253 3254 $query = $db->query(" 3255 SELECT p.pid, p.tid, p.visible, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible 3256 FROM ".TABLE_PREFIX."posts p 3257 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 3258 LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) 3259 WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost != p.pid 3260 "); 3261 while($post = $db->fetch_array($query)) 3262 { 3263 $pids[] = $post['pid']; 3264 3265 if(!isset($thread_counters[$post['tid']])) 3266 { 3267 $thread_counters[$post['tid']] = array( 3268 'replies' => 0, 3269 'unapprovedposts' => 0, 3270 'deletedposts' => 0 3271 ); 3272 } 3273 3274 ++$thread_counters[$post['tid']]['deletedposts']; 3275 if($post['visible'] == 1) 3276 { 3277 ++$thread_counters[$post['tid']]['replies']; 3278 } 3279 else 3280 { 3281 ++$thread_counters[$post['tid']]['unapprovedposts']; 3282 } 3283 3284 if(!isset($forum_counters[$post['fid']])) 3285 { 3286 $forum_counters[$post['fid']] = array( 3287 'num_posts' => 0, 3288 'num_unapproved_posts' => 0, 3289 'num_deleted_posts' => 0 3290 ); 3291 } 3292 3293 // If the thread of this post is deleted then we've already taken into account this counter as implied. 3294 // Updating it again would cause it to double count 3295 if($post['threadvisible'] == 1) 3296 { 3297 ++$forum_counters[$post['fid']]['num_deleted_posts']; 3298 if($post['visible'] == 1) 3299 { 3300 ++$forum_counters[$post['fid']]['num_posts']; 3301 } 3302 else 3303 { 3304 ++$forum_counters[$post['fid']]['num_unapproved_posts']; 3305 } 3306 } 3307 3308 // If post counts enabled in this forum and the thread is approved, subtract 1 3309 if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1 && $post['visible'] == 1) 3310 { 3311 if(!isset($user_counters[$post['uid']])) 3312 { 3313 $user_counters[$post['uid']] = 0; 3314 } 3315 --$user_counters[$post['uid']]; 3316 } 3317 } 3318 3319 if(empty($pids) && empty($threads_to_update)) 3320 { 3321 return false; 3322 } 3323 3324 if(!empty($pids)) 3325 { 3326 $where = "pid IN (".implode(',', $pids).")"; 3327 $db->update_query("posts", $update, $where); 3328 mark_reports($pids, "posts"); 3329 } 3330 3331 $plugins->run_hooks("class_moderation_soft_delete_posts", $pids); 3332 3333 if(is_array($thread_counters)) 3334 { 3335 foreach($thread_counters as $tid => $counters) 3336 { 3337 $counters_update = array( 3338 "unapprovedposts" => "-".$counters['unapprovedposts'], 3339 "replies" => "-".$counters['replies'], 3340 "deletedposts" => "+".$counters['deletedposts'] 3341 ); 3342 3343 update_thread_counters($tid, $counters_update); 3344 update_last_post($tid); 3345 } 3346 } 3347 3348 if(is_array($forum_counters)) 3349 { 3350 foreach($forum_counters as $fid => $counters) 3351 { 3352 $updated_forum_stats = array( 3353 'posts' => "-{$counters['num_posts']}", 3354 'unapprovedposts' => "-{$counters['num_unapproved_posts']}", 3355 'deletedposts' => "+{$counters['num_deleted_posts']}" 3356 ); 3357 update_forum_counters($fid, $updated_forum_stats); 3358 update_forum_lastpost($fid); 3359 } 3360 } 3361 3362 if(!empty($user_counters)) 3363 { 3364 foreach($user_counters as $uid => $counter) 3365 { 3366 update_user_counters($uid, array('postnum' => "{$counter}")); 3367 } 3368 } 3369 3370 return true; 3371 } 3372 3373 /** 3374 * Restore multiple posts 3375 * 3376 * @param array $pids PIDs 3377 * @return boolean 3378 */ 3379 function restore_posts($pids) 3380 { 3381 global $db, $cache, $plugins; 3382 3383 $num_posts = 0; 3384 3385 if(empty($pids)) 3386 { 3387 return false; 3388 } 3389 3390 // Make sure we only have valid values 3391 $pids = array_map('intval', $pids); 3392 3393 $pid_list = implode(',', $pids); 3394 $pids = $threads_to_update = array(); 3395 3396 // Make visible 3397 $update = array( 3398 "visible" => 1, 3399 ); 3400 3401 // We have three cases we deal with in these code segments: 3402 // 1) We're approving specific restored posts 3403 // 1.1) if the thread is deleted 3404 // 1.2) if the thread is restored 3405 // 2) We're restoring the firstpost of the thread, therefore restoring the thread itself 3406 // 3) We're doing both 1 and 2 3407 $query = $db->query(" 3408 SELECT p.tid 3409 FROM ".TABLE_PREFIX."posts p 3410 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 3411 WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost = p.pid AND t.visible = -1 3412 "); 3413 while($post = $db->fetch_array($query)) 3414 { 3415 // This is the first post in the thread so we're approving the whole thread. 3416 $threads_to_update[] = $post['tid']; 3417 } 3418 3419 if(!empty($threads_to_update)) 3420 { 3421 $this->restore_threads($threads_to_update); 3422 } 3423 3424 $thread_counters = $forum_counters = $user_counters = array(); 3425 3426 $query = $db->query(" 3427 SELECT p.pid, p.tid, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible 3428 FROM ".TABLE_PREFIX."posts p 3429 LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) 3430 LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) 3431 WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost != p.pid 3432 "); 3433 while($post = $db->fetch_array($query)) 3434 { 3435 $pids[] = $post['pid']; 3436 3437 if(!isset($thread_counters[$post['tid']])) 3438 { 3439 $thread_counters[$post['tid']] = array( 3440 'replies' => 0 3441 ); 3442 } 3443 3444 ++$thread_counters[$post['tid']]['replies']; 3445 3446 // If the thread of this post is deleted then we've already taken into account this counter as implied. 3447 // Updating it again would cause it to double count 3448 if($post['threadvisible'] == 1) 3449 { 3450 if(!isset($forum_counters[$post['fid']])) 3451 { 3452 $forum_counters[$post['fid']] = array( 3453 'num_posts' => 0 3454 ); 3455 } 3456 ++$forum_counters[$post['fid']]['num_posts']; 3457 } 3458 3459 // If post counts enabled in this forum and the thread is approved, add 1 3460 if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1) 3461 { 3462 if(!isset($user_counters[$post['uid']])) 3463 { 3464 $user_counters[$post['uid']] = 0; 3465 } 3466 ++$user_counters[$post['uid']]; 3467 3468 } 3469 } 3470 3471 if(empty($pids) && empty($threads_to_update)) 3472 { 3473 return false; 3474 } 3475 3476 if(!empty($pids)) 3477 { 3478 $where = "pid IN (".implode(',', $pids).")"; 3479 $db->update_query("posts", $update, $where); 3480 } 3481 3482 $plugins->run_hooks("class_moderation_restore_posts", $pids); 3483 3484 if(is_array($thread_counters)) 3485 { 3486 foreach($thread_counters as $tid => $counters) 3487 { 3488 $counters_update = array( 3489 "deletedposts" => "-".$counters['replies'], 3490 "replies" => "+".$counters['replies'] 3491 ); 3492 update_thread_counters($tid, $counters_update); 3493 update_last_post($tid); 3494 } 3495 } 3496 3497 if(is_array($forum_counters)) 3498 { 3499 foreach($forum_counters as $fid => $counters) 3500 { 3501 $updated_forum_stats = array( 3502 'posts' => "+{$counters['num_posts']}", 3503 'deletedposts' => "-{$counters['num_posts']}" 3504 ); 3505 update_forum_counters($fid, $updated_forum_stats); 3506 update_forum_lastpost($fid); 3507 } 3508 } 3509 3510 if(!empty($user_counters)) 3511 { 3512 foreach($user_counters as $uid => $counter) 3513 { 3514 update_user_counters($uid, array('postnum' => "+{$counter}")); 3515 } 3516 } 3517 3518 return true; 3519 } 3520 3521 /** 3522 * Restore one or more threads 3523 * 3524 * @param array|int $tids Thread ID(s) 3525 * @return boolean true 3526 */ 3527 function restore_threads($tids) 3528 { 3529 global $db, $cache, $plugins; 3530 3531 if(!is_array($tids)) 3532 { 3533 $tids = array($tids); 3534 } 3535 3536 if(empty($tids)) 3537 { 3538 return false; 3539 } 3540 3541 // Make sure we only have valid values 3542 $tids = array_map('intval', $tids); 3543 3544 $tid_list = $forum_counters = $user_counters = $posts_to_restore = array(); 3545 3546 $tids_list = implode(",", $tids); 3547 $query = $db->simple_select("threads", "*", "tid IN ($tids_list)"); 3548 3549 while($thread = $db->fetch_array($query)) 3550 { 3551 if($thread['visible'] != -1) 3552 { 3553 continue; 3554 } 3555 $tid_list[] = $thread['tid']; 3556 3557 $forum = get_forum($thread['fid']); 3558 3559 if(!isset($forum_counters[$forum['fid']])) 3560 { 3561 $forum_counters[$forum['fid']] = array( 3562 'num_posts' => 0, 3563 'num_threads' => 0, 3564 'num_deleted_posts' => 0, 3565 'num_unapproved_posts' => 0 3566 ); 3567 } 3568 3569 if(!isset($user_counters[$thread['uid']])) 3570 { 3571 $user_counters[$thread['uid']] = array( 3572 'num_posts' => 0, 3573 'num_threads' => 0 3574 ); 3575 } 3576 3577 ++$forum_counters[$forum['fid']]['num_threads']; 3578 $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Remove implied visible from count 3579 $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1; 3580 $forum_counters[$forum['fid']]['num_unapproved_posts'] += $thread['unapprovedposts']; 3581 3582 if($forum['usepostcounts'] != 0) 3583 { 3584 // On approving thread restore user post counts 3585 $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"); 3586 while($counter = $db->fetch_array($query2)) 3587 { 3588 if(!isset($user_counters[$counter['uid']])) 3589 { 3590 $user_counters[$counter['uid']] = array( 3591 'num_posts' => 0, 3592 'num_threads' => 0 3593 ); 3594 } 3595 $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; 3596 } 3597 } 3598 3599 if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') 3600 { 3601 ++$user_counters[$thread['uid']]['num_threads']; 3602 } 3603 3604 $posts_to_restore[] = $thread['firstpost']; 3605 } 3606 3607 if(!empty($tid_list)) 3608 { 3609 $tid_moved_list = ""; 3610 $comma = ""; 3611 foreach($tid_list as $tid) 3612 { 3613 $tid_moved_list .= "{$comma}'moved|{$tid}'"; 3614 $comma = ","; 3615 } 3616 $tid_list = implode(',', $tid_list); 3617 $update = array( 3618 "visible" => 1 3619 ); 3620 $db->update_query("threads", $update, "tid IN ($tid_list)"); 3621 // Restore redirects, too 3622 $redirect_tids = array(); 3623 $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); 3624 while($redirect_tid = $db->fetch_field($query, 'tid')) 3625 { 3626 $redirect_tids[] = $redirect_tid; 3627 } 3628 if(!empty($redirect_tids)) 3629 { 3630 $this->restore_threads($redirect_tids); 3631 } 3632 if(!empty($posts_to_restore)) 3633 { 3634 $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_restore).")"); 3635 } 3636 3637 $plugins->run_hooks("class_moderation_restore_threads", $tids); 3638 3639 if(is_array($forum_counters)) 3640 { 3641 foreach($forum_counters as $fid => $counters) 3642 { 3643 // Update stats 3644 $update_array = array( 3645 "threads" => "+{$counters['num_threads']}", 3646 "posts" => "+{$counters['num_posts']}", 3647 "unapprovedposts" => "+{$counters['num_unapproved_posts']}", 3648 "deletedposts" => "-{$counters['num_deleted_posts']}", 3649 "deletedthreads" => "-{$counters['num_threads']}" 3650 ); 3651 update_forum_counters($fid, $update_array); 3652 update_forum_lastpost($fid); 3653 } 3654 } 3655 3656 if(!empty($user_counters)) 3657 { 3658 foreach($user_counters as $uid => $counters) 3659 { 3660 $update_array = array( 3661 "postnum" => "+{$counters['num_posts']}", 3662 "threadnum" => "+{$counters['num_threads']}", 3663 ); 3664 update_user_counters($uid, $update_array); 3665 } 3666 } 3667 } 3668 return true; 3669 } 3670 3671 /** 3672 * Soft delete one or more threads 3673 * 3674 * @param array|int Thread ID(s) 3675 * @return boolean 3676 */ 3677 function soft_delete_threads($tids) 3678 { 3679 global $db, $cache, $plugins; 3680 3681 if(!is_array($tids)) 3682 { 3683 $tids = array($tids); 3684 } 3685 3686 if(empty($tids)) 3687 { 3688 return false; 3689 } 3690 3691 // Make sure we only have valid values 3692 $tids = array_map('intval', $tids); 3693 3694 $tid_list = implode(',', $tids); 3695 $tid_moved_list = ""; 3696 $comma = ""; 3697 foreach($tids as $tid) 3698 { 3699 $tid_moved_list .= "{$comma}'moved|{$tid}'"; 3700 $comma = ","; 3701 } 3702 3703 $forum_counters = $user_counters = $posts_to_delete = array(); 3704 3705 $tids_list = implode(",", $tids); 3706 $query = $db->simple_select("threads", "*", "tid IN ($tids_list)"); 3707 3708 while($thread = $db->fetch_array($query)) 3709 { 3710 $forum = get_forum($thread['fid']); 3711 3712 if($thread['visible'] == 1 || $thread['visible'] == 0) 3713 { 3714 if(!isset($forum_counters[$forum['fid']])) 3715 { 3716 $forum_counters[$forum['fid']] = array( 3717 'num_posts' => 0, 3718 'num_threads' => 0, 3719 'num_deleted_threads' => 0, 3720 'num_deleted_posts' => 0, 3721 'unapproved_threads' => 0, 3722 'unapproved_posts' => 0 3723 ); 3724 } 3725 3726 if(!isset($user_counters[$thread['uid']])) 3727 { 3728 $user_counters[$thread['uid']] = array( 3729 'num_posts' => 0, 3730 'num_threads' => 0 3731 ); 3732 } 3733 3734 ++$forum_counters[$forum['fid']]['num_deleted_threads']; 3735 $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1; 3736 3737 if($thread['visible'] == 1) 3738 { 3739 ++$forum_counters[$forum['fid']]['num_threads']; 3740 $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Add implied invisible to count 3741 $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['unapprovedposts']; 3742 } 3743 else 3744 { 3745 ++$forum_counters[$forum['fid']]['unapproved_threads']; 3746 $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['replies']+$thread['deletedposts']+$thread['unapprovedposts']+1; // Add implied invisible to count 3747 $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['deletedposts']; 3748 } 3749 3750 // On unapproving thread update user post counts 3751 if($thread['visible'] == 1 && $forum['usepostcounts'] != 0) 3752 { 3753 $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"); 3754 while($counter = $db->fetch_array($query2)) 3755 { 3756 if(!isset($user_counters[$counter['uid']])) 3757 { 3758 $user_counters[$counter['uid']] = array( 3759 'num_posts' => 0, 3760 'num_threads' => 0 3761 ); 3762 } 3763 $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; 3764 } 3765 } 3766 3767 if($thread['visible'] == 1 && $forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') 3768 { 3769 ++$user_counters[$thread['uid']]['num_threads']; 3770 } 3771 } 3772 $posts_to_delete[] = $thread['firstpost']; 3773 } 3774 3775 $update = array( 3776 "visible" => -1 3777 ); 3778 $db->update_query("threads", $update, "tid IN ($tid_list)"); 3779 // Soft delete redirects, too 3780 $redirect_tids = array(); 3781 $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); 3782 3783 mark_reports($tids, "threads"); 3784 3785 while($redirect_tid = $db->fetch_field($query, 'tid')) 3786 { 3787 $redirect_tids[] = $redirect_tid; 3788 } 3789 if(!empty($redirect_tids)) 3790 { 3791 $this->soft_delete_threads($redirect_tids); 3792 } 3793 if(!empty($posts_to_delete)) 3794 { 3795 $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_delete).")"); 3796 } 3797 3798 $plugins->run_hooks("class_moderation_soft_delete_threads", $tids); 3799 3800 if(is_array($forum_counters)) 3801 { 3802 foreach($forum_counters as $fid => $counters) 3803 { 3804 // Update stats 3805 $update_array = array( 3806 "threads" => "-{$counters['num_threads']}", 3807 "unapprovedthreads" => "-{$counters['unapproved_threads']}", 3808 "posts" => "-{$counters['num_posts']}", 3809 "unapprovedposts" => "-{$counters['unapproved_posts']}", 3810 "deletedposts" => "+{$counters['num_deleted_posts']}", 3811 "deletedthreads" => "+{$counters['num_deleted_threads']}" 3812 ); 3813 update_forum_counters($fid, $update_array); 3814 update_forum_lastpost($fid); 3815 } 3816 } 3817 3818 if(!empty($user_counters)) 3819 { 3820 foreach($user_counters as $uid => $counters) 3821 { 3822 $update_array = array( 3823 "postnum" => "-{$counters['num_posts']}", 3824 "threadnum" => "-{$counters['num_threads']}", 3825 ); 3826 update_user_counters($uid, $update_array); 3827 } 3828 } 3829 3830 return true; 3831 } 3832 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup | Cross-referenced by PHPXref |