* Invision Power Services * IP.Board v3.1.4 * Moderator actions * Last Updated: $Date: 2010-10-20 09:03:17 -0400 (Wed, 20 Oct 2010) $ * * * @author $Author: ips_terabyte $ * @copyright (c) 2001 - 2009 Invision Power Services, Inc. * @license http://www.invisionpower.com/community/board/license.html * @package IP.Board * @subpackage Forums * @link http://www.invisionpower.com * @version $Revision: 7003 $ * * @todo [Future] Get rid of init method, determine data dynamically (necessary for any centralized moderation routine, e.g. from search results) */ if ( ! defined( 'IN_IPB' ) ) { print "

Incorrect access

You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files."; exit(); } class moderatorLibrary { /** * Moderator information * * @var array Array of moderator details */ public $moderator = array(); /** * Forum information * * @var array Array of forum details */ public $forum = array(); /** * Topic information * * @var array Array of topic details */ public $topic = array(); /** * Error code encountered * * @var string Error code */ public $error = ""; /** * Automatically update forum info * * @var boolean Whether or not to automatically update forum info */ public $auto_update = false; /** * Stored statement * * @var string Stored multi-mod statement */ public $stm = ""; /** * Upload directory * * @var string Upload directory */ public $upload_dir = "./uploads"; /**#@+ * Registry Object Shortcuts * * @var object */ protected $registry; protected $DB; protected $settings; protected $request; protected $lang; protected $member; protected $memberData; protected $cache; protected $caches; /**#@-*/ /** * Class entry point * * @param object Registry reference * @return void */ public function __construct( ipsRegistry $registry ) { /* Make objects */ $this->registry = $registry; $this->DB = $this->registry->DB(); $this->settings =& $this->registry->fetchSettings(); $this->request =& $this->registry->fetchRequest(); $this->lang = $this->registry->getClass('class_localization'); $this->member = $this->registry->member(); $this->memberData =& $this->registry->member()->fetchMemberData(); $this->cache = $this->registry->cache(); $this->caches =& $this->registry->cache()->fetchCaches(); /* Check for class_forums */ if( ipsRegistry::isClassLoaded('class_forums') !== TRUE ) { $classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'forums' ) . "/sources/classes/forums/class_forums.php", 'class_forums', 'forums' ); $this->registry->setClass( 'class_forums', new $classToLoad( $registry ) ); $this->registry->class_forums->forumsInit(); } $this->upload_dir = $this->settings['upload_dir']; } /** * Initialization * * @param array Forum array * @param array [Optional] Topic array * @param array [Optional] Moderator array * @return boolean True */ public function init($forum="", $topic="", $moderator="") { $this->forum = $forum; if ( is_array($topic) ) { $this->topic = $topic; } if ( is_array($moderator) ) { $this->moderator = $moderator; } return true; } /** * Toggle approve status of content by a member * WARNING: This is a utility function. No permission checks are performed. * * @param int Member ID (topic starter / post author) * @param boolean TRUE = approve, FALSE = unapprove * @param string Option [ topics / replies / all ] * @param int [ Optional: last X hours worth of data ] * @return boolean */ public function toggleApproveMemberContent( $memberID, $approve=FALSE, $option, $date=0 ) { $memberID = intval( $memberID ); $date = intval( $date ); $timeCut = ( $date ) ? ( time() - ( $date * 3600 ) ) : 0; $topicFind = ''; $postFind = ''; $forumIDs = array(); $topicIDs = array(); if ( ! $memberID ) { return FALSE; } switch ( $option ) { default: case 'all': case 'both': case 'topics': $postFind = 'author_id=' . $memberID . ' AND new_topic=0'; $postFind .= ( $timeCut ) ? ' AND post_date > ' . $timeCut : ''; $topicFind = 'starter_id=' . $memberID; $topicFind .= ( $timeCut ) ? ' AND start_date > ' . $timeCut : ''; break; case 'replies': case 'posts': $postFind = 'author_id=' . $memberID . ' AND new_topic=0'; $postFind .= ( $timeCut ) ? ' AND post_date > ' . $timeCut : ''; break; } //----------------------------------------- // Find forums.. //----------------------------------------- if ( $topicFind ) { $this->DB->build( array( 'select' => $this->DB->buildDistinct( 'forum_id' ), 'from' => 'topics', 'where' => $topicFind ) ); $this->DB->execute(); while( $row = $this->DB->fetch() ) { $forumIDs[ $row['forum_id'] ] = $row['forum_id']; } } if ( $postFind ) { $this->DB->build( array( 'select' => $this->DB->buildDistinct( 't.forum_id' ) . ',t.tid', 'from' => array( 'posts' => 'p' ), 'where' => $postFind, 'add_join' => array( array( 'select' => '', 'from' => array( 'topics' => 't' ), 'where' => 'p.topic_id=t.tid' ) ) ) ); $this->DB->execute(); while( $row = $this->DB->fetch() ) { $forumIDs[ $row['forum_id'] ] = $row['forum_id']; $topicIDs[ $row['tid'] ] = $row['tid']; } } //----------------------------------------- // Run... //----------------------------------------- if ( $topicFind ) { $this->DB->update( 'topics', array( 'approved' => ( $approve === TRUE ) ? 1 : 0 ), $topicFind ); } if ( $postFind ) { $this->DB->update( 'posts', array( 'queued' => ( $approve === TRUE ) ? 0 : 1 ), $postFind ); } if ( count( $topicIDs ) ) { foreach( $topicIDs as $id ) { $this->rebuildTopic( $id ); } } if ( count( $forumIDs ) ) { foreach( $forumIDs as $id ) { $this->forumRecount( $id ); } } $this->statsRecount(); return TRUE; } /** * Delete content by a member * WARNING: This is a utility function. No permission checks are performed. * NOTE: This function is unfinished and unused. Might be useful to finish it for 3.1 * The problem is mostly deleting posts when the trash can is in-use. You'd need to split them * and create a new topic for each which would be incredibly expensive without breaking it down into * batches. * * @todo [Future] Deleting topics and posts is bloody expensive. This limits to 150 ids or it could bust the IN() SQL statement * Probably need to find a neater way to do this.. Task? * * @param int Member ID (topic starter / post author) * @param string Option [ topics / replies / all ] * @param int [ Optional: last X hours worth of data ] * @return boolean */ public function deleteMemberContent( $memberID, $option, $date=0 ) { $memberID = intval( $memberID ); $date = intval( $date ); $timeCut = ( $date ) ? ( time() - ( $date * 3600 ) ) : 0; $topicFind = ''; $postFind = ''; $topicIDs = array(); $postIDs = array(); $forumIDs = array(); if ( ! $memberID ) { return FALSE; } switch ( $option ) { default: case 'all': case 'both': case 'topics': $postFind = 'author_id=' . $memberID . ' AND new_topic=0'; $postFind .= ( $timeCut ) ? ' AND post_date > ' . $timeCut : ''; $topicFind = 'starter_id=' . $memberID; $topicFind .= ( $timeCut ) ? ' AND start_date > ' . $timeCut : ''; break; case 'replies': case 'posts': $postFind = 'author_id=' . $memberID . ' AND new_topic=0'; $postFind .= ( $timeCut ) ? ' AND post_date > ' . $timeCut : ''; break; } //----------------------------------------- // Run... //----------------------------------------- if ( $topicFind ) { $this->DB->build( array( 'select' => 'tid, forum_id', 'from' => 'topics', 'where' => $topicFind, 'order' => 'start_date DESC', 'limit' => array( 0, 150 ) ) ); $this->DB->execute(); while( $row = $this->DB->fetch() ) { $topicIDs[] = $row['tid']; $forumIDs[ $row['forum_id'] ] = $row['forum_id']; } } else if ( $postFind ) { $this->DB->build( array( 'select' => 'pid, topic_id', 'from' => 'posts', 'where' => $postFind, 'order' => 'post_date DESC', 'limit' => array( 0, 150 ) ) ); $this->DB->execute(); while( $row = $this->DB->fetch() ) { $postIDs[] = $row['pid']; $_topicids[ $row['topic_id'] ] = $row['topic_id']; } if ( is_array( $_topicids ) AND count( $_topicids ) ) { $this->DB->build( array( 'select' => 'tid, forum_id', 'from' => 'topics', 'where' => 'tid IN (' . implode( ',', $_topicids ) . ')', 'order' => 'start_date DESC', 'limit' => array( 0, 150 ) ) ); $this->DB->execute(); while( $row = $this->DB->fetch() ) { $forumIDs[ $row['forum_id'] ] = $row['forum_id']; } } } //----------------------------------------- // Set up trash can //----------------------------------------- $this->_takeOutTrash(); //----------------------------------------- // Delete topics... //----------------------------------------- if ( is_array( $topicIDs ) AND count( $topicIDs ) ) { if ( $this->trash_forum ) { //----------------------------------------- // Move, don't delete //----------------------------------------- $this->topicMove( $topicIDs, 0, $this->trash_forum ); $this->forumRecount( $this->trash_forum ); } else { $this->topicDelete( $topicIDs, 1 ); } } //----------------------------------------- // Delete posts... //----------------------------------------- if ( is_array( $postIDs ) AND count( $postIDs ) ) { if ( $this->trash_forum ) { //----------------------------------------- // Move, don't delete //----------------------------------------- //$this->topicMove( $topicsIDs, 0, $this->trash_forum ); $this->forumRecount( $this->trash_forum ); } else { $this->postDelete( $postIDs ); } } if ( count( $forumIDs ) ) { foreach( $forumIDs as $id ) { $this->registry->class_forums->allForums[ $id ]['_update_deletion'] = 1; $this->forumRecount( $id ); } } $this->statsRecount(); return TRUE; } /** * Delete / undelete posts * * @param array Array of Post IDs * @param boolean Approve (TRUE) / Unapprove (FALSE) * @param int Fix so posts can only come from a specific topic ID * @return boolean */ public function postToggleSoftDelete( $postIDs, $delete=FALSE, $reason='', $topicIDFix=0 ) { //----------------------------------------- // INIT //----------------------------------------- $_restoreTopic = 1; $_deletedPost = 0; if ( $delete === TRUE ) { $_restoreTopic = -1; $_deletedPost = 2; } $_topics = array(); $_forumIDs = array(); $_pids = IPSLib::cleanIntArray( $postIDs ); $_tids = array(); //----------------------------------------- // Fetch distinct topic IDs //----------------------------------------- $this->DB->build( array( 'select' => $this->DB->buildDistinct( 'p.topic_id' ), 'from' => array( 'posts' => 'p' ), 'where' => 'p.pid IN (' . implode( ',', $postIDs ) . ')', 'add_join' => array( array( 'select' => 't.*', 'from' => array( 'topics' => 't' ), 'where' => 'p.topic_id=t.tid', 'type' => 'inner' ) ) ) ); $this->DB->execute(); while( $row = $this->DB->fetch() ) { $_topics[ $row['topic_id'] ] = $row; } //----------------------------------------- // Did we get the first post too? //----------------------------------------- foreach( $_topics as $tid => $topicData ) { /* Fix to a topic? */ if ( $topicIDFix AND ( $topicIDFix != $tid ) ) { continue; } $_forumIDs[] = $topicData['forum_id']; if ( in_array( $topicData['topic_firstpost'], $_pids ) ) { $this->DB->update( 'topics', array( 'approved' => $_restoreTopic ), 'tid=' . $tid ); $tmp = $_pids; $_pids = array(); foreach( $tmp as $t ) { if ( $t != $topicData['topic_firstpost'] ) { $_pids[] = $t; } else { $_tids[ $topicData['tid'] ] = $topicData['tid']; } } } } if ( count( $_pids ) ) { $this->DB->update( 'posts', array( 'queued' => $_deletedPost ), 'pid IN (' . implode( ",", $_pids ) . ')' ); if ( $_deletedPost ) { foreach( $_pids as $_p ) { /* Add entry to delete log innit */ IPSDeleteLog::addEntry( $_p, 'post', $reason, $this->memberData ); } } else { /* Un-deleting, so delete */ IPSDeleteLog::removeEntries( $_pids, 'post' ); } } if ( count( $_tids ) ) { if ( $_deletedPost ) { foreach( $_tids as $_t ) { IPSDeleteLog::addEntry( $_t, 'topic', $reason, $this->memberData ); } } else { /* Un-deleting, so delete */ IPSDeleteLog::removeEntries( $_tids, 'topic' ); } } if ( $delete ) { foreach( $_topics as $tid => $topicData ) { $this->addModerateLog( $topicData['forum_id'], $tid, 0, $topicData['title'], sprintf( $this->lang->words['acp_softdeleted_posts'], count( $_pids ), $topicData['title'] ) ); } } else { foreach( $_topics as $tid => $topicData ) { $this->addModerateLog( $topicData['forum_id'], $tid, 0, $topicData['title'], sprintf( $this->lang->words['acp_unsoftdeleted_posts'], count( $_pids ), $topicData['title'] ) ); } } foreach( $_topics as $tid => $topicData ) { $this->rebuildTopic( $tid ); } if ( count( $_forumIDs ) ) { foreach( $_forumIDs as $_fid ) { $this->forumRecount( $_fid ); } } $this->statsRecount(); return TRUE; } /** * Approve / unapprove posts * * @param array Array of Post IDs * @param boolean Approve (TRUE) / Unapprove (FALSE) * @param int Fix so posts can only come from a specific topic ID * @return boolean */ public function postToggleApprove( $postIDs, $approve=FALSE, $topicIDFix=0 ) { //----------------------------------------- // INIT //----------------------------------------- $_approveTopic = 1; $_queuedPost = 0; if ( $approve === FALSE ) { $_approveTopic = 0; $_queuedPost = 1; } $_topics = array(); $_forumIDs = array(); $_pids = IPSLib::cleanIntArray( $postIDs ); $_tids = array(); //----------------------------------------- // Fetch distinct topic IDs //----------------------------------------- $this->DB->build( array( 'select' => $this->DB->buildDistinct( 'p.topic_id' ), 'from' => array( 'posts' => 'p' ), 'where' => 'p.pid IN (' . implode( ',', $postIDs ) . ')', 'add_join' => array( array( 'select' => 't.*', 'from' => array( 'topics' => 't' ), 'where' => 'p.topic_id=t.tid', 'type' => 'inner' ) ) ) ); $this->DB->execute(); while( $row = $this->DB->fetch() ) { $_topics[ $row['topic_id'] ] = $row; } //----------------------------------------- // Did we get the first post too? //----------------------------------------- foreach( $_topics as $tid => $topicData ) { /* Fix to a topic? */ if ( $topicIDFix AND ( $topicIDFix != $tid ) ) { continue; } $_forumIDs[] = $topicData['forum_id']; if ( in_array( $topicData['topic_firstpost'], $_pids ) ) { $this->DB->update( 'topics', array( 'approved' => $_approveTopic ), 'tid=' . $tid ); /* Unapprove the topic, but not the first post? */ //if ( $_queuedPost ) //{ $tmp = $_pids; $_pids = array(); foreach( $tmp as $t ) { if ( $t != $topicData['topic_firstpost'] ) { $_pids[] = $t; } else { $_tids[ $topicData['tid'] ] = $topicData['tid']; } } //} } } if ( count( $_pids ) ) { $this->DB->update( 'posts', array( 'queued' => $_queuedPost ), 'pid IN (' . implode( ",", $_pids ) . ')' ); } if ( $approve ) { foreach( $_topics as $tid => $topicData ) { $this->addModerateLog( $topicData['forum_id'], $tid, 0, $topicData['title'], sprintf( $this->lang->words['acp_approved_posts'], count( $_pids ), $topicData['title'] ) ); } if( count($_pids) ) { $this->clearModQueueTable( 'post', $_pids, true ); } if( count($_tids) ) { $this->clearModQueueTable( 'topic', $_tids, true ); } } else { foreach( $_topics as $tid => $topicData ) { $this->addModerateLog( $topicData['forum_id'], $tid, 0, $topicData['title'], sprintf( $this->lang->words['acp_unapproved_posts'], count( $_pids ), $topicData['title'] ) ); } } foreach( $_topics as $tid => $topicData ) { $this->rebuildTopic( $tid ); } if ( count( $_forumIDs ) ) { foreach( $_forumIDs as $_fid ) { $this->forumRecount( $_fid ); } } $this->statsRecount(); return TRUE; } /** * Clear out the mod-queue table appropriately * * @param string [topic|post] Type of item moved * @param mixed ID of topic or post, or array of ids * @param boolean Was content approved? * @return void */ public function clearModQueueTable( $type, $typeId, $approved=false ) { //----------------------------------------- // Get post class.. //----------------------------------------- require_once( IPSLib::getAppDir( 'forums' ) . '/sources/classes/post/classPost.php' ); $classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'forums' ) . '/sources/classes/post/classPostForms.php', 'classPostForms', 'forums' ); $_postClass = new $classToLoad( $this->registry ); //----------------------------------------- // Are we operating on one id, or an array //----------------------------------------- if( is_array($typeId) ) { $where = "type_id IN(" . implode( ',', IPSLib::cleanIntArray($typeId) ) . ")"; } else { $where = "type_id=" . intval($typeId); } //----------------------------------------- // Was content deleted or moved to trash forum //----------------------------------------- if( ! $approved ) { $this->DB->delete( 'mod_queued_items', "type='{$type}' AND {$where}" ); } //----------------------------------------- // No, then we are approving content //----------------------------------------- else { //----------------------------------------- // Working with posts? //----------------------------------------- if( $type == 'post' ) { IPSDebug::fireBug( 'info', array( 'type is post' ) ); $this->DB->build( array( 'select' => 'm.id', 'from' => array( 'mod_queued_items' => 'm' ), 'where' => "m.type='{$type}' AND m.{$where}", 'add_join' => array( array( 'select' => 'p.pid, p.post, p.author_id, p.post_date, p.topic_id', 'from' => array( 'posts' => 'p' ), 'where' => 'p.pid=m.type_id', 'type' => 'left', ), array( 'select' => 't.title, t.forum_id', 'from' => array( 'topics' => 't' ), 'where' => 't.tid=p.topic_id', 'type' => 'left', ), ) ) ); $outer = $this->DB->execute(); while( $r = $this->DB->fetch($outer) ) { $member = IPSMember::load( $r['author_id'], 'extendedProfile,groups' ); $_postClass->setPublished( true ); $_postClass->setAuthor( $member ); $_postClass->setForumData( $this->registry->class_forums->allForums[ $r['forum_id'] ] ); $_postClass->incrementUsersPostCount(); $_postClass->sendOutTrackedTopicEmails( $r['topic_id'], $r['post'], $member['members_display_name'], time() - $this->settings['session_expiration'], $member['member_id'] ); $this->DB->delete( 'mod_queued_items', 'id=' . $r['id'] ); } } else { IPSDebug::fireBug( 'info', array( 'type is topic' ) ); $this->DB->build( array( 'select' => 'm.id', 'from' => array( 'mod_queued_items' => 'm' ), 'where' => "m.type='{$type}' AND m.{$where}", 'add_join' => array( array( 'select' => 't.tid, t.title, t.starter_id, t.forum_id', 'from' => array( 'topics' => 't' ), 'where' => 't.tid=m.type_id', 'type' => 'left', ), array( 'select' => 'p.pid, p.post, p.post_date', 'from' => array( 'posts' => 'p' ), 'where' => 'p.pid=t.topic_firstpost', 'type' => 'left', ), ) ) ); $outer = $this->DB->execute(); while( $r = $this->DB->fetch($outer) ) { $member = IPSMember::load( $r['starter_id'], 'extendedProfile,groups' ); $_postClass->setPublished( true ); $_postClass->setAuthor( $member ); $_postClass->setForumData( $this->registry->class_forums->allForums[ $r['forum_id'] ] ); $_postClass->incrementUsersPostCount(); $_postClass->sendOutTrackedForumEmails( $r['forum_id'], $r['tid'], $r['title'], $this->registry->class_forums->allForums[ $r['forum_id'] ]['name'], $r['post'], $member['member_id'], $member['members_display_name'] ); $this->DB->delete( 'mod_queued_items', 'id=' . $r['id'] ); } } } $this->addModerateLog( $this->request['f'], $this->request['t'], $this->request['p'], $this->topic['title'], sprintf( $this->lang->words['modqueue_table_clear'], $type, is_array($typeId) ? implode( ', ', $typeId ) : $typeId ) ); } /** * Delete a post * * @param mixed Post id | Array of post ids * @return array Topic IDs */ public function postDelete($id) { $posts = array(); $attach_tid = array(); $attach_ids = array(); $topics = array(); $fids = array(); $this->error = ""; if ( is_array( $id ) ) { $id = IPSLib::cleanIntArray( $id ); if ( count($id) > 0 ) { $pid = " IN(" . implode( ",", $id ) . ")"; } else { return false; } } else { if ( intval($id) ) { $pid = "={$id}"; } else { return false; } } /* Remove from deletion log */ $_ids = ( is_array( $id ) ) ? $id : array( $id ); IPSDeleteLog::removeEntries( $_ids, 'post', TRUE ); //----------------------------------------- // Get Stuff //----------------------------------------- $this->DB->build( array( 'select' => 'pid, topic_id, new_topic', 'from' => 'posts', 'where' => 'pid' . $pid ) ); $q = $this->DB->execute(); while ( $r = $this->DB->fetch( $q ) ) { $posts[ $r['pid'] ] = $r['topic_id']; $topics[ $r['topic_id'] ] = 1; /* Delete from rep cache */ $this->DB->delete( 'reputation_cache', "app='forums' AND type='pid' AND type_id={$r['pid']}" ); $this->DB->delete( 'reputation_index', "app='forums' AND type='pid' AND type_id={$r['pid']}" ); } //----------------------------------------- // Is there an attachment to this post? //----------------------------------------- $classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'core' ) . '/sources/classes/attach/class_attach.php', 'class_attach' ); $class_attach = new $classToLoad( $this->registry ); $class_attach->type = 'post'; $class_attach->init(); $class_attach->bulkRemoveAttachment( array_keys( $posts ) ); //----------------------------------------- // delete the post //----------------------------------------- $this->DB->delete( 'posts', "pid" . $pid ); /* Remove cache content */ IPSContentCache::drop( 'post', array_keys( $posts ) ); //----------------------------------------- // Update the stats //----------------------------------------- $this->cache->rebuildCache( 'stats', 'global' ); //----------------------------------------- // Update all relevant topics //----------------------------------------- foreach( array_keys($topics) as $tid ) { $this->rebuildTopic( $tid ); } if ( count( $topics ) ) { $this->DB->build( array( 'select' => 'forum_id', 'from' => 'topics', 'where' => 'tid IN (' . implode( ',', array_keys( $topics ) ) . ')' ) ); $i = $this->DB->execute(); while( $row = $this->DB->fetch( $i ) ) { $fids[ $row['forum_id'] ] = $row['forum_id']; } } if ( count( $fids ) ) { foreach( $fids as $f ) { $this->forumRecount( $f ); } } /* Run moderation sync */ $this->runModSync( 'postDelete', array_keys( $posts ) ); //----------------------------------------- // Log and return //----------------------------------------- $pid = str_replace( array( 'IN', '(', ')', '=' ), '', $pid ); $this->addModerateLog( "", "", "", $pid, sprintf( $this->lang->words['multi_post_delete'], $_ids ) ); return array_keys($topics); } /** * Rebuild a topic * * @param integer Topic id * @param boolean Rebuild forum afterwards * @return boolean Rebuild complete */ public function rebuildTopic( $tid, $doforum=1 ) { /* Topic ID */ $tid = intval( $tid ); if( $this->settings['post_order_column'] != 'post_date' ) { $this->settings[ 'post_order_column'] = 'pid' ; } if( $this->settings['post_order_sort'] != 'desc' ) { $this->settings[ 'post_order_sort'] = 'asc' ; } //----------------------------------------- // Get the correct number of replies //----------------------------------------- $posts = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as posts', 'from' => 'posts', 'where' => "topic_id={$tid} and queued=0" ) ); $pcount = intval( $posts['posts'] - 1 ); //----------------------------------------- // Get the correct number of queued replies //----------------------------------------- $qposts = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as posts', 'from' => 'posts', 'where' => "topic_id={$tid} and queued=1" ) ); $qpcount = intval( $qposts['posts'] ); //----------------------------------------- // Get the correct number of soft deleted replies //----------------------------------------- $dposts = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as posts', 'from' => 'posts', 'where' => "topic_id={$tid} and queued=2" ) ); $dpcount = intval( $dposts['posts'] ); //----------------------------------------- // Get last post info //----------------------------------------- $last_post = $this->DB->buildAndFetch( array( 'select' => 'p.post_date, p.topic_id, p.author_id, p.author_name, p.pid', 'from' => array( 'posts' => 'p' ), 'where' => 'p.topic_id=' . $tid . ' AND p.queued=0', 'order' => $this->settings['post_order_column'] . ' DESC', 'limit' => array( 1 ), 'add_join' => array( array( 'select' => 't.forum_id, t.title', 'from' => array( 'topics' => 't' ), 'where' => 't.tid=p.topic_id', 'type' => 'left' ), array( 'select' => 'm.member_id, m.members_display_name', 'from' => array( 'members' => 'm' ), 'where' => 'm.member_id=p.author_id', 'type' => 'left' ), ) ) ); $last_poster_name = $last_post['members_display_name'] ? $last_post['members_display_name'] : $last_post['author_name']; //----------------------------------------- // Get first post info //----------------------------------------- $first_post = $this->DB->buildAndFetch( array( 'select' => 'p.post_date, p.author_id, p.author_name, p.pid', 'from' => array( 'posts' => 'p' ), 'where' => "p.topic_id={$tid}", 'order' => "p." . $this->settings['post_order_column'] . " ASC", 'limit' => array(0,1), 'add_join' => array( array( 'select' => 'm.member_id, m.members_display_name', 'from' => array( 'members' => 'm' ), 'where' => "p.author_id=m.member_id", 'type' => 'left' ) ) ) ); $first_poster_name = $first_post['members_display_name'] ? $first_post['members_display_name'] : $first_post['author_name']; $_last_poster_name = $last_poster_name ? $last_poster_name : ( $pcount > 0 ? $this->lang->words['global_guestname'] : $first_poster_name ); //----------------------------------------- // Get number of attachments //----------------------------------------- $attach = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as count', 'from' => array( 'attachments' => 'a' ), 'where' => "p.topic_id={$tid} AND a.attach_rel_module='post'", 'add_join' => array( array( 'from' => array( 'posts' => 'p' ), 'where' => 'p.pid=a.attach_rel_id', 'type' => 'left' ) ) ) ); //----------------------------------------- // Update topic //----------------------------------------- $this->DB->force_data_type = array( 'starter_name' => 'string', 'last_poster_name' => 'string' ); $this->DB->update( 'topics', array( 'last_post' => intval($last_post['post_date'] ? $last_post['post_date'] : $first_post['post_date']), 'last_poster_id' => intval($last_post['author_id'] ? $last_post['author_id'] : ( $pcount > 0 ? 0 : $first_post['author_id'] )), 'last_poster_name' => $_last_poster_name, 'topic_queuedposts' => intval($qpcount), 'topic_deleted_posts' => intval($dpcount), 'posts' => intval($pcount), 'starter_id' => intval($first_post['author_id']), 'starter_name' => $first_poster_name, 'seo_first_name' => IPSText::makeSeoTitle( $first_poster_name ), 'seo_last_name' => IPSText::makeSeoTitle( $_last_poster_name ), 'start_date' => intval($first_post['post_date']), 'topic_firstpost' => intval($first_post['pid']), 'topic_hasattach' => intval($attach['count']), 'title_seo' => IPSText::makeSeoTitle( $last_post['title'] ) ), 'tid=' . $tid ); //----------------------------------------- // Update first post //----------------------------------------- if( ( ! isset( $first_post['new_topic'] ) OR $first_post['new_topic'] != 1 ) and $first_post['pid'] ) { $this->DB->update( 'posts', array( 'new_topic' => 0 ), 'topic_id=' . $tid, true ); $this->DB->update( 'posts', array( 'new_topic' => 1 ), 'pid=' . $first_post['pid'], true ); } //----------------------------------------- // If we deleted the last post in a topic that was // the last post in a forum, best update that :D //----------------------------------------- if( ( $this->registry->class_forums->allForums[ $last_post['forum_id'] ]['last_id'] == $tid ) AND ( $doforum == 1 ) ) { $tt = $this->DB->buildAndFetch( array( 'select' => 'title, tid, last_post, last_poster_id, last_poster_name', 'from' => 'topics', 'where' => 'forum_id=' . $last_post['forum_id'] . ' and approved=1', 'order' => 'last_post desc', 'limit' => array( 1 ) ) ); $dbs = array( 'last_title' => $tt['title'] ? $tt['title'] : "", 'last_id' => $tt['tid'] ? $tt['tid'] : 0, 'last_post' => $tt['last_post'] ? $tt['last_post'] : 0, 'last_poster_name' => $tt['last_poster_name'] ? $tt['last_poster_name'] : "", 'last_poster_id' => $tt['last_poster_id'] ? $tt['last_poster_id'] : 0, 'seo_last_title' => IPSText::makeSeoTitle( $tt['title'] ), 'seo_last_name' => IPSText::makeSeoTitle( $tt['last_poster_name'] ), ); if( $this->registry->class_forums->allForums[ $this->forum['id'] ]['newest_id'] == $tid ) { $sort_key = $this->registry->class_forums->allForums[ $this->forum['id'] ]['sort_key']; $tt = $this->DB->buildAndFetch( array( 'select' => 'title, tid', 'from' => 'topics', 'where' => 'forum_id=' . $this->forum['id'] . ' and approved=1', 'order' => 'start_date desc', 'limit' => array( 1 ) ) ); $dbs['newest_id'] = $tt['tid'] ? $tt['tid'] : 0; $dbs['newest_title'] = $tt['title'] ? $tt['title'] : ""; $dbs['seo_last_title'] = IPSText::makeSeoTitle( $tt['title'] ); } $this->DB->force_data_type = array( 'last_poster_name' => 'string', 'seo_last_title' => 'string', 'seo_last_name' => 'string', 'last_title' => 'string', 'newest_title' => 'string' ); $this->DB->update( 'forums', $dbs, "id=" . intval($this->forum['id']) ); } return true; } /** * Add a reply to a topic * * @param string Post contnet * @param array Array of topic ids to apply this reply to * @param boolean Increment post count? * @return boolean Reply added * @todo [Future] Would better using the new posting libs so that topic subs, etc are triggered maybe. * Though, do we really want topic subs triggered on a multi-mod? */ public function topicAddReply($post="", $tids=array(), $incpost=0) { if ( $post == "" ) { return false; } if ( count( $tids ) < 1 ) { return false; } $post = array( 'author_id' => $this->memberData['member_id'], 'use_sig' => 1, 'use_emo' => 1, 'ip_address' => $this->member->ip_address, 'post_date' => time(), 'icon_id' => 0, 'post' => $post, 'author_name' => $this->memberData['members_display_name'], 'topic_id' => "", 'queued' => 0, 'post_htmlstate' => 2, ); //----------------------------------------- // Add posts... //----------------------------------------- $seen_fids = array(); $add_posts = 0; foreach( $tids as $row ) { $tid = intval($row[0]); $fid = intval($row[1]); $pa = array(); $ta = array(); if ( ! in_array( $fid, $seen_fids ) ) { $seen_fids[] = $fid; } if ( $tid and $fid ) { $pa = $post; $pa['topic_id'] = $tid; $this->DB->insert( 'posts', $pa ); $_pid = $this->DB->getInsertId(); /* Add to cache */ IPSContentCache::update( $_pid, 'post', $post['post'], FALSE ); $ta = array ( 'last_poster_id' => $this->memberData['member_id'], 'last_poster_name' => $this->memberData['members_display_name'], 'seo_last_name' => IPSText::makeSeoTitle( $this->memberData['members_display_name'] ), 'last_post' => $pa['post_date'], ); $this->DB->force_data_type = array( 'last_poster_name' => 'string', 'seo_last_name' => 'string' ); $this->DB->buildAndFetch( array( 'update' => 'topics', 'set' => $this->DB->compileUpdateString( $ta ) . ", posts=posts+1", 'where' => 'tid='.$tid ) ); $add_posts++; //----------------------------------------- // Mark as read for current viewer //----------------------------------------- $this->registry->classItemMarking->markRead( array( 'forumID' => $fid, 'itemID' => $tid ) ); } } if ( $this->auto_update != false ) { if ( count($seen_fids) > 0 ) { foreach( $seen_fids as $id ) { $this->forumRecount( $id ); } } } if ( $add_posts > 0 ) { $this->cache->rebuildCache( 'stats', 'global' ); //----------------------------------------- // Update current members stuff //----------------------------------------- $pcount = ""; $member_group_id = ""; if ( ($this->forum['inc_postcount']) and ($incpost != 0) ) { //----------------------------------------- // Increment the users post count //----------------------------------------- $pcount = "posts=posts+" . $add_posts . ", "; //----------------------------------------- // Are we checking for auto promotion? //----------------------------------------- if ($this->memberData['g_promotion'] != '-1&-1') { list($gid, $gposts) = explode( '&', $this->memberData['g_promotion'] ); if ( $gid > 0 and $gposts > 0 ) { if ( $this->memberData['posts'] + $add_posts >= $gposts ) { $member_group_id = "member_group_id='{$gid}', "; } } } } $this->DB->buildAndFetch( array( 'update' => 'members', 'set' => $pcount . $member_group_id . "last_post=" . time(), 'where' => "member_id=" . $this->memberData['member_id'] ) ); } return true; } /** * Close a topic * * @param integer Topic id * @return boolean */ public function topicClose( $id ) { $this->stmInit(); $this->stmAddClose(); $this->stmExec($id); return TRUE; } /** * Open a topic * * @param integer Topic id * @return boolean */ public function topicOpen($id) { $this->stmInit(); $this->stmAddOpen(); $this->stmExec($id); return TRUE; } /** * Pin a topic * * @param integer Topic id * @return boolean */ public function topicPin($id) { $this->stmInit(); $this->stmAddPin(); $this->stmExec($id); return TRUE; } /** * Unpin a topic * * @param integer Topic id * @return boolean */ public function topicUnpin($id) { $this->stmInit(); $this->stmAddUnpin(); $this->stmExec($id); return TRUE; } /** * Delete a topic * * @param mixed Topic id | Array of topic ids * @param boolean Skip updating the stats * @return boolean */ public function topicDelete( $id, $nostats=0 ) { $posts = array(); $attach = array(); $this->error = ""; if ( is_array( $id ) ) { $id = IPSLib::cleanIntArray( $id ); if ( count($id) > 0 ) { $tid = " IN(" . implode( ",", $id ) . ")"; } else { return false; } } else { if ( intval($id) ) { $tid = "={$id}"; } else { return false; } } /* Remove from deletion log */ $_ids = ( is_array( $id ) ) ? $id : array( $id ); IPSDeleteLog::removeEntries( $_ids, 'topic', TRUE ); //----------------------------------------- // Remove polls assigned to this topic //----------------------------------------- $this->DB->delete( 'polls', "tid" . $tid ); $this->DB->delete( 'voters', "tid" . $tid ); $this->DB->delete( 'tracker', "topic_id" . $tid ); $this->DB->delete( 'topic_ratings', "rating_tid" . $tid ); $this->DB->delete( 'topic_views', "views_tid" . $tid ); $this->DB->delete( 'topics', "tid" . $tid ); //----------------------------------------- // Get PIDS for attachment deletion //----------------------------------------- $this->DB->build( array( 'select' => 'pid', 'from' => 'posts', 'where' => "topic_id" . $tid ) ); $this->DB->execute(); while ( $r = $this->DB->fetch() ) { $posts[] = $r['pid']; } /* Remove cache content */ IPSContentCache::drop( 'post', $posts ); //----------------------------------------- // Remove the attachments //----------------------------------------- $classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'core' ) . '/sources/classes/attach/class_attach.php', 'class_attach' ); $class_attach = new $classToLoad( $this->registry ); $class_attach->type = 'post'; $class_attach->init(); $class_attach->bulkRemoveAttachment( $posts ); //----------------------------------------- // Remove the posts //----------------------------------------- $this->DB->delete( 'posts', "topic_id" . $tid ); $this->DB->delete( 'reputation_cache', "app='forums' AND type='pid' AND type_id " . $tid ); $this->DB->delete( 'reputation_index', "app='forums' AND type='pid' AND type_id " . $tid ); //----------------------------------------- // Recount forum... //----------------------------------------- if ( !$nostats ) { if ( $this->forum['id'] ) { $this->registry->class_forums->allForums[ $this->forum['id'] ]['_update_deletion'] = 1; $this->forumRecount( $this->forum['id'] ); } $this->statsRecount(); } /* Run moderation sync */ $this->runModSync( 'topicDelete', $_ids ); return TRUE; } /** * Move a topic * * @param mixed Topic id | Array of topic ids * @param integer Source forum * @param integer Move to forum * @param boolean Leave the 'link' * @return boolean */ public function topicMove($topics, $source=0, $moveto=0, $leavelink=0) { $this->error = ""; $source = intval($source); $moveto = intval($moveto); $forumIDSQL = ( $source ) ? " forum_id={$source} AND " : ''; if ( is_array( $topics ) ) { $topics = IPSLib::cleanIntArray( $topics ); if ( count($topics) > 0 ) { $tid = " IN(" . implode( ",", $topics ) . ")"; } else { return false; } //----------------------------------------- // Mark as read in new forum //----------------------------------------- /* Bug #21052 */ //foreach( $topics as $topicId ) //{ // $this->registry->classItemMarking->markRead( array( 'forumID' => $moveto, 'itemID' => $topicId ), 'forums' ); //} } else { if ( intval($topics) ) { $tid = "={$topics}"; } else { return false; } //----------------------------------------- // Mark as read in new forum //----------------------------------------- $this->registry->classItemMarking->markRead( array( 'forumID' => $moveto, 'itemID' => $topics ), 'forums' ); } //----------------------------------------- // Update the topic //----------------------------------------- $this->DB->update( 'topics', array( 'forum_id' => $moveto ), $forumIDSQL . "tid" . $tid ); //----------------------------------------- // Update the polls //----------------------------------------- $this->DB->update( 'polls', array( 'forum_id' => $moveto ), $forumIDSQL . "tid" . $tid ); //----------------------------------------- // Are we leaving a stink er link? //----------------------------------------- if ( $leavelink AND $source ) { $this->DB->build( array( 'select' => '*', 'from' => 'topics', 'where' => "tid" . $tid ) ); $oq = $this->DB->execute(); while ( $row = $this->DB->fetch($oq) ) { $this->DB->force_data_type = array( 'title' => 'string', 'starter_name' => 'string', 'last_poster_name' => 'string', 'seo_last_name' => 'string' ); $this->DB->insert( 'topics', array ( 'title' => $row['title'], 'description' => $row['description'], 'state' => 'link', 'posts' => 0, 'views' => 0, 'starter_id' => $row['starter_id'], 'start_date' => $row['start_date'], 'starter_name' => $row['starter_name'], 'seo_first_name' => IPSText::makeSeoTitle( $row['starter_name'] ), 'last_post' => $row['last_post'], 'forum_id' => $source, 'approved' => 1, 'pinned' => 0, 'moved_to' => $row['tid'] . '&' . $moveto, 'last_poster_id' => $row['last_poster_id'], 'last_poster_name' => $row['last_poster_name'], 'seo_last_name' => IPSText::makeSeoTitle( $row['starter_name'] ), ) ); } } //----------------------------------------- // Sort out subscriptions //----------------------------------------- $trid_to_delete = array(); $this->DB->build( array( 'select' => 'tr.*', 'from' => array( 'tracker' => 'tr' ), 'where' => 'tr.topic_id' . $tid, 'add_join' => array( array( 'select' => 't.tid, t.forum_id', 'from' => array( 'topics' => 't' ), 'where' => 't.tid=tr.topic_id', 'type' => 'left', ), array( 'select' => 'm.member_id, m.member_group_id, m.org_perm_id', 'from' => array( 'members' => 'm' ), 'where' => 'm.member_id=tr.member_id', 'type' => 'left', ), array( 'select' => 'g.g_id, g.g_perm_id', 'from' => array( 'groups' => 'g' ), 'where' => 'g.g_id=m.member_group_id', 'type' => 'left', ), ) ) ); $this->DB->execute(); while ( $r = $this->DB->fetch() ) { //----------------------------------------- // Match the perm group against forum_mask //----------------------------------------- $perm_id = $r['org_perm_id'] ? $r['org_perm_id'] : $r['g_perm_id']; if ( $this->registry->permissions->check( 'read', $this->registry->class_forums->allForums[ $moveto ], explode( ',', IPSText::cleanPermString( $perm_id ) ) ) !== TRUE ) { $trid_to_delete[] = $r['trid']; } } if ( count($trid_to_delete) > 0 ) { $this->DB->delete( 'tracker', "trid IN(" . implode( ',', $trid_to_delete ) . ")" ); } return true; } /** * Delete / undelete posts * * @param array Array of Post IDs * @param boolean Approve (TRUE) / Unapprove (FALSE) * @return boolean */ public function topicToggleSoftDelete( $topicIds, $delete=FALSE, $reason='' ) { //----------------------------------------- // INIT //----------------------------------------- $_restoreTopic = 1; if ( $delete === TRUE ) { $_restoreTopic = -1; } $_topics = array(); $_forumIDs = array(); $_tids = IPSLib::cleanIntArray( $topicIds ); //----------------------------------------- // Fetch distinct topic IDs //----------------------------------------- $this->DB->build( array( 'select' => '*', 'from' => 'topics', 'where' => 'tid IN (' . implode( ',', $_tids ) . ')' ) ); $this->DB->execute(); while( $row = $this->DB->fetch() ) { $_topics[ $row['tid'] ] = $row; $_forumIDs[ $row['forum_id'] ] = $row['forum_id']; } //----------------------------------------- // Did we get the first post too? //----------------------------------------- foreach( $_topics as $tid => $topicData ) { $this->DB->update( 'topics', array( 'approved' => $_restoreTopic ), 'tid=' . $tid ); if ( $delete ) { IPSDeleteLog::addEntry( $tid, 'topic', $reason, $this->memberData ); } /* Rebuild topic */ $this->rebuildTopic( $tid ); /* Mod log */ $this->addModerateLog( $topicData['forum_id'], $tid, 0, $topicData['title'], sprintf( $this->lang->words['acp_altered_topics'], array(), $topicData['title'] ) ); } /* Restoring */ if ( ! $delete ) { /* Un-deleting, so delete */ IPSDeleteLog::removeEntries( $_tids, 'post' ); } if ( count( $_forumIDs ) ) { foreach( $_forumIDs as $_fid ) { $this->forumRecount( $_fid ); } } $this->statsRecount(); return TRUE; } /** * Recount total topics and replies for site statistics * * @return boolean */ public function statsRecount() { $this->cache->rebuildCache( 'stats', 'global' ); return true; } /** * Recount a forum * * @return boolean */ public function forumRecount( $fid="" ) { $fid = intval($fid); if ( ! $fid ) { if ( $this->forum['id'] ) { $fid = $this->forum['id']; } else { return false; } } //----------------------------------------- // Get the topics.. //----------------------------------------- $topics = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as count', 'from' => 'topics', 'where' => "approved=1 and forum_id={$fid}" ) ); //----------------------------------------- // Get the QUEUED topics.. //----------------------------------------- $queued_topics = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as count', 'from' => 'topics', 'where' => "approved=0 and forum_id={$fid}" ) ); //----------------------------------------- // Get the DELETED topics.. //----------------------------------------- $deleted_topics = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as count', 'from' => 'topics', 'where' => "approved=-1 and forum_id={$fid}" ) ); //----------------------------------------- // Get the posts.. //----------------------------------------- $posts = $this->DB->buildAndFetch( array( 'select' => 'SUM(posts) as replies', 'from' => 'topics', 'where' => "approved=1 and forum_id={$fid}" ) ); //----------------------------------------- // Get the QUEUED posts.. //----------------------------------------- $queued_posts = $this->DB->buildAndFetch( array( 'select' => 'SUM(topic_queuedposts) as replies', 'from' => 'topics', 'where' => "forum_id={$fid}" ) ); //----------------------------------------- // Get the DELETED posts.. //----------------------------------------- $deleted_posts = $this->DB->buildAndFetch( array( 'select' => 'SUM(topic_deleted_posts) as replies', 'from' => 'topics', 'where' => "forum_id={$fid}" ) ); //----------------------------------------- // Get the forum last poster.. //----------------------------------------- $last_post = $this->DB->buildAndFetch( array( 'select' => 'tid, title, last_poster_id, last_poster_name, seo_last_name, last_post', 'from' => 'topics', 'where' => "approved=1 and forum_id={$fid}", 'order' => 'last_post DESC', 'limit' => array( 1 ) ) ); $newest_topic = $this->DB->buildAndFetch( array( 'select' => 'title, tid, seo_first_name', 'from' => 'topics', 'where' => 'forum_id=' . $fid . ' and approved=1', 'order' => 'start_date desc', 'limit' => array( 1 ) ) ); $lastXTopics = $this->registry->class_forums->lastXFreeze( $this->registry->class_forums->buildLastXTopicIds( $fid, FALSE ) ); //----------------------------------------- // Reset this forums stats //----------------------------------------- $dbs = array( 'name_seo' => IPSText::makeSeoTitle( $this->registry->class_forums->allForums[ $fid ]['name'] ), 'last_poster_id' => intval($last_post['last_poster_id']), 'last_poster_name' => $last_post['last_poster_name'], 'seo_last_name' => IPSText::makeSeoTitle( $last_post['last_poster_name'] ), 'last_post' => intval($last_post['last_post']), 'last_title' => $last_post['title'], 'seo_last_title' => IPSText::makeSeoTitle( $last_post['title'] ), 'last_id' => intval($last_post['tid']), 'topics' => intval($topics['count']), 'posts' => intval($posts['replies']), 'queued_topics' => intval($queued_topics['count']), 'queued_posts' => intval($queued_posts['replies']), 'deleted_posts' => intval($deleted_posts['replies']), 'deleted_topics' => intval($deleted_topics['count']), 'newest_id' => intval($newest_topic['tid']), 'newest_title' => $newest_topic['title'], 'last_x_topic_ids' => $lastXTopics ); if ( $this->registry->class_forums->allForums[ $fid ]['_update_deletion'] ) { $dbs['forum_last_deletion'] = time(); } $this->DB->force_data_type = array( 'last_poster_name' => 'string', 'last_title' => 'string', 'newest_title' => 'string', 'seo_last_title' => 'string', 'seo_last_name' => 'string' ); $this->DB->update( 'forums', $dbs, "id=" . $fid ); return true; } /** * Multi-statement init * * @return boolean */ public function stmInit() { $this->stm = array(); return true; } /** * Multi-statement execute * * @param mixed Id | Array of ids * @return boolean */ public function stmExec($id) { if ( count($this->stm) < 1 ) { return false; } $final_array = array(); foreach( $this->stm as $real_array ) { foreach( $real_array as $k => $v ) { $final_array[ $k ] = $v; } } if ( is_array($id) ) { $id = IPSLib::cleanIntArray( $id ); if ( count($id) > 0 ) { $this->DB->update( 'topics', $final_array, "tid IN(" . implode( ",", $id ) . ")" ); } else { return false; } } else if ( intval($id) != "" ) { $this->DB->update( 'topics', $final_array, "tid=" . intval($id) ); } else { return false; } return true; } /** * Multi-statement pin topic * * @return boolean */ public function stmAddPin() { $this->stm[] = array( 'pinned' => 1 ); return TRUE; } /** * Multi-statement unpin topic * * @return boolean */ public function stmAddUnpin() { $this->stm[] = array( 'pinned' => 0 ); return TRUE; } /** * Multi-statement close topic * * @return boolean */ public function stmAddClose() { $this->stm[] = array( 'state' => 'closed' ); $this->stm[] = array( 'topic_open_time' => 0 ); $this->stm[] = array( 'topic_close_time' => 0 ); return TRUE; } /** * Multi-statement open topic * * @return boolean */ public function stmAddOpen() { $this->stm[] = array( 'state' => 'open' ); $this->stm[] = array( 'topic_open_time' => 0 ); $this->stm[] = array( 'topic_close_time' => 0 ); return TRUE; } /** * Multi-statement update topic title * * @return boolean */ public function stmAddTitle($new_title='') { if ( $new_title == "" ) { return FALSE; } $this->stm[] = array( 'title' => $new_title ); return TRUE; } /** * Multi-statement update topic description topic * * @return boolean */ public function stmAddDesc($new_desc='') { if ( $new_desc == "" ) { return FALSE; } $this->stm[] = array( 'description' => $new_desc ); return TRUE; } /** * Multi-statement approve topic * * @return boolean */ public function stmAddApprove() { $this->stm[] = array( 'approved' => 1 ); return TRUE; } /** * Multi-statement unapprove topic * * @return boolean */ public function stmAddUnapprove() { $this->stm[] = array( 'approved' => 0 ); return TRUE; } /** * Create 'where' clause for SQL forum pruning * * @return boolean */ public function sqlPruneCreate( $forum_id, $starter_id="", $topic_state="", $post_min="", $date_exp="", $ignore_pin="" ) { $sql = 'forum_id=' . intval($forum_id); if ( intval($date_exp) ) { $sql .= " AND last_post < " . intval( $date_exp ); } if ( intval($starter_id) ) { $sql .= " AND starter_id=" . intval( $starter_id ); } if ( intval($post_min) ) { $sql .= " AND posts < " . intval( $post_min ); } if ($topic_state != 'all') { if ($topic_state) { $sql .= " AND state='{$topic_state}'"; } } if ( $ignore_pin != "" ) { $sql .= " AND pinned=0"; } return $sql; } /** * Determines if current member is authorized to use multi-mod * * @return boolean */ public function mmAuthorize() { $pass_go = FALSE; if ( $this->memberData['member_id'] ) { if ( $this->memberData['g_is_supmod'] ) { $pass_go = TRUE; } else if ( $this->moderator['can_mm'] == 1 ) { $pass_go = TRUE; } } return $pass_go; } /** * Checks if multi-mod is allowed in a specified forum * * @return boolean */ public function mmCheckIdInForum( $fid, $mm_data) { $retval = FALSE; if ( $mm_data['mm_forums'] == '*' OR strstr( "," . $mm_data['mm_forums'] . ",", "," . $fid . "," ) ) { $retval = TRUE; } return $retval; } /** * Add an entry to the moderator log * * @param integer Forum id * @param integer Topic id * @param string Topic title * @param string Title to add to moderator log * @return boolean */ public function addModerateLog($fid, $tid, $pid, $t_title, $mod_title='Unknown') { $this->DB->force_data_type = array( 'member_name' => 'string' ); $this->DB->insert( 'moderator_logs', array ( 'forum_id' => intval($fid), 'topic_id' => intval($tid), 'post_id' => intval($pid), 'member_id' => $this->memberData['member_id'], 'member_name' => $this->memberData['members_display_name'], 'ip_address' => $this->member->ip_address, 'http_referer' => htmlspecialchars( my_getenv('HTTP_REFERER') ), 'ctime' => time(), 'topic_title' => $t_title, 'action' => $mod_title, 'query_string' => htmlspecialchars( my_getenv('QUERY_STRING') ), ) ); return TRUE; } /** * Run the forum mod sync system * * @param string Function to call * @return bool */ public function runModSync( $func ) { /* ipsRegistry::$applications only contains apps with a public title #15785 */ $app_cache = $this->registry->cache()->getCache('app_cache'); /* Params */ $params = func_get_args(); array_shift( $params ); /* Loop through applications */ foreach( $app_cache as $app_dir => $app ) { if( IPSLib::appIsInstalled( $app_dir ) ) { /* Setup */ $_file = IPSLib::getAppDir( $app['app_directory'] ) . '/extensions/forumDataSync.php'; $_class = $app['app_directory'] . '_forumDataSync'; /* Check for the file */ if( file_exists( $_file ) ) { /* Get the file */ require_once( $_file ); /* Check for the class */ if( class_exists( $_class ) ) { /* Create an object */ $_obj = new $_class( $this->registry ); /* Check for the module */ if( method_exists( $_obj, $func ) ) { /* Call it */ call_user_func_array( array( $_obj, $func ), $params ); } } } } } } /** * Setup the trash can forum * * @author Brandon Farber * @return void */ private function _takeOutTrash() { if ( $this->settings['forum_trash_can_enable'] and $this->settings['forum_trash_can_id'] ) { if ( $this->registry->class_forums->allForums[ $this->settings['forum_trash_can_id'] ]['sub_can_post'] ) { if ( $this->memberData['g_access_cp'] ) { $this->trash_forum = $this->settings['forum_trash_can_use_admin'] ? $this->settings['forum_trash_can_id'] : 0; } else if ( $this->memberData['g_is_supmod'] ) { $this->trash_forum = $this->settings['forum_trash_can_use_smod'] ? $this->settings['forum_trash_can_id'] : 0; } else if ( $this->memberData['is_mod'] ) { $this->trash_forum = $this->settings['forum_trash_can_use_mod'] ? $this->settings['forum_trash_can_id'] : 0; } else { $this->trash_forum = $this->settings['forum_trash_can_id']; } } } } }