diff options
| author | modela bitweaver <spiderr@bitweaver.org> | 2021-02-01 13:30:02 -0500 |
|---|---|---|
| committer | modela bitweaver <spiderr@bitweaver.org> | 2021-02-01 13:30:02 -0500 |
| commit | 6acff0fba312ac169fe02882c03ba5f1de4b27ae (patch) | |
| tree | d84530cfe960691cc724ebac2bed605a3b3cd75f /includes | |
| parent | 6e4ff4522532da0af3daead83ed469081a01e18c (diff) | |
| download | boards-6acff0fba312ac169fe02882c03ba5f1de4b27ae.tar.gz boards-6acff0fba312ac169fe02882c03ba5f1de4b27ae.tar.bz2 boards-6acff0fba312ac169fe02882c03ba5f1de4b27ae.zip | |
move classes to includes/classes and use PKG_CLASS/INCLUDE_PATH constants
Diffstat (limited to 'includes')
| -rw-r--r-- | includes/classes/BitBoard.php | 866 | ||||
| -rw-r--r-- | includes/classes/BitBoardPost.php | 468 | ||||
| -rw-r--r-- | includes/classes/BitBoardTopic.php | 778 |
3 files changed, 2112 insertions, 0 deletions
diff --git a/includes/classes/BitBoard.php b/includes/classes/BitBoard.php new file mode 100644 index 0000000..1c62a35 --- /dev/null +++ b/includes/classes/BitBoard.php @@ -0,0 +1,866 @@ +<?php +/** + * $Header$ + * $Id$ + * + * BitBoard class to illustrate best practices when creating a new bitweaver package that + * builds on core bitweaver functionality, such as the Liberty CMS engine + * + * @author spider <spider@steelsun.com> + * @version $Revision$ + * @package boards + */ + +/** + * required setup + */ +require_once( LIBERTY_PKG_PATH.'LibertyMime.php' ); + +/** +* This is used to uniquely identify the object +*/ +define( 'BITBOARD_CONTENT_TYPE_GUID', 'bitboard' ); + +/** + * @package boards + */ +class BitBoard extends LibertyMime { + /** + * Primary key for our mythical BitBoard class object & table + * @public + */ + public $mBitBoardId; + + /** + * During initialisation, be sure to call our base constructors + **/ + function __construct( $pBitBoardId=NULL, $pContentId=NULL ) { + parent::__construct(); + $this->mBitBoardId = (int)$pBitBoardId; + $this->mContentId = (int)$pContentId; + $this->mContentTypeGuid = BITBOARD_CONTENT_TYPE_GUID; + $this->registerContentType( BITBOARD_CONTENT_TYPE_GUID, array( + 'content_type_guid' => BITBOARD_CONTENT_TYPE_GUID, + 'content_name' => 'Message Board', + 'handler_class' => 'BitBoard', + 'handler_package' => 'boards', + 'handler_file' => 'BitBoard.php', + 'maintainer_url' => 'http://www.bitweaver.org' + )); + + // Permission setup + $this->mViewContentPerm = 'p_boards_read'; + $this->mCreateContentPerm = 'p_boards_create'; + $this->mUpdateContentPerm = 'p_boards_update'; + $this->mAdminContentPerm = 'p_boards_admin'; + $this->mExpungeContentPerm = 'p_boards_remove'; + } + + /** + * Load the data from the database + * @param pParamHash be sure to pass by reference in case we need to make modifcations to the hash + **/ + function load( $pContentId = NULL, $pPluginParams = NULL ) { + if( $this->verifyId( $this->mBitBoardId ) || $this->verifyId( $this->mContentId ) ) { + // LibertyContent::load()assumes you have joined already, and will not execute any sql! + // This is a significant performance optimization + $lookupColumn = $this->verifyId( $this->mBitBoardId ) ? 'board_id' : 'content_id'; + $bindVars = array(); + $selectSql = $joinSql = $whereSql = ''; + array_push( $bindVars, (int)($lookupId = @BitBase::verifyId( $this->mBitBoardId ) ? $this->mBitBoardId : $this->mContentId) ); + $this->getServicesSql( 'content_load_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + $query = "SELECT s.*, lc.*, " . + "uue.`login` AS modifier_user, uue.`real_name` AS modifier_real_name, " . + "uuc.`login` AS creator_user, uuc.`real_name` AS creator_real_name " . + "$selectSql " . + "FROM `".BIT_DB_PREFIX."boards` s " . + "INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON( lc.`content_id` = s.`content_id` ) $joinSql" . + "LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON( uue.`user_id` = lc.`modifier_user_id` )" . + "LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON( uuc.`user_id` = lc.`user_id` )" . + "WHERE s.`$lookupColumn`=? $whereSql"; + $result = $this->mDb->query( $query, $bindVars ); + + if( $result && $result->numRows() ) { + $this->mInfo = $result->fields; + $this->mContentId = $result->fields['content_id']; + $this->mBitBoardId = $result->fields['board_id']; + + $this->mInfo['creator'] =( isset( $result->fields['creator_real_name'] )? $result->fields['creator_real_name'] : $result->fields['creator_user'] ); + $this->mInfo['editor'] =( isset( $result->fields['modifier_real_name'] )? $result->fields['modifier_real_name'] : $result->fields['modifier_user'] ); + $this->mInfo['display_url'] = $this->getDisplayUrl(); + $this->parseData(); + + LibertyMime::load(); + } + } + return( count( $this->mInfo ) ); + } + + function lookupByMigrateBoard( $pMigrateBoardId ) { + global $gBitDb; + $ret = NULL; + if( BitBase::verifyId( $pMigrateBoardId ) ) { + $ret = $gBitDb->getOne( "SELECT `board_id` FROM `".BIT_DB_PREFIX."boards` bb WHERE `migrate_board_id`=?", array( $pMigrateBoardId ) ); + } + return $ret; + } + + /** + * Any method named Store inherently implies data will be written to the database + * @param pParamHash be sure to pass by reference in case we need to make modifcations to the hash + * This is the ONLY method that should be called in order to store( create or update )an bitboard! + * It is very smart and will figure out what to do for you. It should be considered a black box. + * + * @param array pParams hash of values that will be used to store the page + * + * @return bool TRUE on success, FALSE if store could not occur. If FALSE, $this->mErrors will have reason why + * + * @access public + **/ + function store( &$pParamHash ) { + if( $this->verify( $pParamHash )&& LibertyMime::store( $pParamHash ) ) { + $table = BIT_DB_PREFIX."boards"; + $this->StartTrans(); + if( $this->mBitBoardId ) { + $locId = array( "board_id" => $pParamHash['board_id'] ); + $result = $this->mDb->associateUpdate( $table, $pParamHash['board_store'], $locId ); + } else { + $pParamHash['board_store']['content_id'] = $pParamHash['content_id']; + if( @$this->verifyId( $pParamHash['board_id'] ) ) { + // if pParamHash['board_id'] is set, some is requesting a particular board_id. Use with caution! + $pParamHash['board_store']['board_id'] = $pParamHash['board_id']; + } else { + $pParamHash['board_store']['board_id'] = $this->mDb->GenID( 'boards_board_id_seq' ); + } + $this->mBitBoardId = $pParamHash['board_store']['board_id']; + + $result = $this->mDb->associateInsert( $table, $pParamHash['board_store'] ); + $result = $this->mDb->associateInsert( BIT_DB_PREFIX."boards_map",array('board_content_id'=>$pParamHash['board_store']['content_id'],'topic_content_id'=>$pParamHash['board_store']['content_id'])); + if( !empty( $pParamHash['boards_mailing_list'] ) ) { + global $gBitSystem, $gBitUser; + require_once( UTIL_PKG_INC.'mailman_lib.php' ); + if( $gBitSystem->getConfig( 'boards_sync_mail_server' ) ) { + if( !($error = mailman_newlist( array( 'listname' => $pParamHash['boards_mailing_list'], 'listhost' => $gBitSystem->getConfig( 'boards_email_host', $gBitSystem->getConfig( 'kernel_server_name' ) ), 'admin-password'=>$pParamHash['boards_mailing_list_password'], 'listadmin-addr'=>$gBitUser->getField( 'email' ) ) )) ) { + $this->storePreference( 'boards_mailing_list', !empty( $pParamHash['boards_mailing_list'] ) ? $pParamHash['boards_mailing_list'] : NULL ); + $this->storePreference( 'boards_mailing_list_password', $pParamHash['boards_mailing_list_password'] ); + // Subscribe the owner + mailman_addmember( $this->getPreference( 'boards_mailing_list'), $gBitUser->getField('email') ); + // If we have an inbox then subscribe it as a moderator + if( $this->getBoardSyncInbox() ) { + mailman_addmember( $this->getPreference( 'boards_mailing_list' ), $this->getBoardSyncInbox() ); + mailman_setmoderator( $this->getPreference( 'boards_mailing_list' ), $this->getBoardSyncInbox() ); + } + $this->storePreference( 'board_sync_list_address', $this->getBoardMailingList() ); + } else { + $this->mErrors['mailing_list'] = $error; + } + } + } + } + + if( count( $this->mErrors ) == 0 ) { + $this->CompleteTrans(); + $this->load(); + } else { + $this->mDb->RollbackTrans(); + $this->mContentId = NULL; + $this->mBitBoardId = NULL; + } + } + return( count( $this->mErrors )== 0 ); + } + + /** + * Make sure the data is safe to store + * @param pParamHash be sure to pass by reference in case we need to make modifcations to the hash + * This function is responsible for data integrity and validation before any operations are performed with the $pParamHash + * NOTE: This is a PRIVATE METHOD!!!! do not call outside this class, under penalty of death! + * + * @param array pParams reference to hash of values that will be used to store the page, they will be modified where necessary + * + * @return bool TRUE on success, FALSE if verify failed. If FALSE, $this->mErrors will have reason why + * + * @access private + **/ + function verify( &$pParamHash ) { + // make sure we're all loaded up of we have a mBitBoardId + if( $this->verifyId( $this->mBitBoardId ) && empty( $this->mInfo ) ) { + $this->load(); + } + + if( @$this->verifyId( $this->mInfo['content_id'] ) ) { + $pParamHash['content_id'] = $this->mInfo['content_id']; + } + + // It is possible a derived class set this to something different + if( empty( $pParamHash['content_type_guid'] ) ) { + $pParamHash['content_type_guid'] = $this->mContentTypeGuid; + } + + if( @$this->verifyId( $pParamHash['content_id'] ) ) { + $pParamHash['board_store']['content_id'] = $pParamHash['content_id']; + } + + if( @$this->verifyId( $pParamHash['migrate_board_id'] ) ) { + $pParamHash['board_store']['migrate_board_id'] = $pParamHash['migrate_board_id']; + } +/* board description seems to have been removed in favor of liberty_content data + // check some lengths, if too long, then truncate + if( $this->isValid() && !empty( $this->mInfo['description'] ) && empty( $pParamHash['description'] ) ) { + // someone has deleted the description, we need to null it out + $pParamHash['board_store']['description'] = ''; + } else if( empty( $pParamHash['description'] ) ) { + unset( $pParamHash['description'] ); + } else { + $pParamHash['board_store']['description'] = substr( $pParamHash['description'], 0, 200 ); + } +*/ + if( !empty( $pParamHash['data'] ) ) { + $pParamHash['edit'] = $pParamHash['data']; + } + + // check for name issues, first truncate length if too long + if( !empty( $pParamHash['title'] ) ) { + if( empty( $this->mBitBoardId ) ) { + if( empty( $pParamHash['title'] ) ) { + $this->mErrors['title'] = 'You must enter a name for this page.'; + } else { + $pParamHash['content_store']['title'] = substr( $pParamHash['title'], 0, 160 ); + } + } else { + $pParamHash['content_store']['title'] =( isset( $pParamHash['title'] ) )? substr( $pParamHash['title'], 0, 160 ): ''; + } + } else if( empty( $pParamHash['title'] ) ) { + // no name specified + $this->mErrors['title'] = 'You must specify a name'; + } + + return( count( $this->mErrors )== 0 ); + } + + + /** + * Prepare data for preview + */ + function preparePreview( $pParamHash ) { + global $gBitSystem, $gBitUser; + + if( empty( $pParamHash['user_id'] ) ) { + $pParamHash['user_id'] = $gBitUser->mUserId; + } + + if( isset( $pParamHash["title"] ) ) { + $this->mInfo["title"] = $pParamHash["title"]; + } + + if( isset( $pParamHash["description"] ) ) { + $this->mInfo["description"] = $pParamHash["description"]; + } + + if( isset( $pParamHash["format_guid"] ) ) { + $this->mInfo['format_guid'] = $pParamHash["format_guid"]; + } + + if( isset( $pParamHash["edit"] ) ) { + $this->mInfo["data"] = $pParamHash["edit"]; + $this->mInfo['parsed_data'] = $this->parseData(); + } + } + + + /** + * This function removes a bitboard entry + **/ + function expunge() { + $ret = FALSE; + if( $this->isValid() ) { + $this->StartTrans(); + $mailingList = $this->getPreference( 'boards_mailing_list' ); + $query = "DELETE FROM `".BIT_DB_PREFIX."boards_map` WHERE `board_content_id` = ?"; + $result = $this->mDb->query( $query, array( $this->mContentId ) ); + $query = "DELETE FROM `".BIT_DB_PREFIX."boards` WHERE `content_id` = ?"; + $result = $this->mDb->query( $query, array( $this->mContentId ) ); + if( LibertyMime::expunge() ) { + if( $mailingList ) { + require_once( UTIL_PKG_INC.'mailman_lib.php' ); + if( $error = mailman_rmlist( $mailingList ) ) { + $this->mErrors['mailing_list'] = $error; + } + } + $ret = TRUE; + $this->CompleteTrans(); + } else { + $this->mDb->RollbackTrans(); + } + } + return $ret; + } + + /** + * Make sure bitboard is loaded and valid + **/ + function isValid() { + return( $this->verifyId( $this->mBitBoardId ) && $this->verifyId( $this->mContentId ) ); + } + + function getAllMap() { + $b = new BitBoard(); + $listHash = array(); + $l = $b->getList($listHash); + $ret = array(); + foreach ($l as $k => $boardd) { + $board = new BitBoard($boardd['board_id']); + $board->mInfo=$boardd; + $ret['map'][$k]=$boardd; + $ret['map'][$k]['map'] = $board->getMap(); + $ret['map'][$k]['integrity'] = $board->verifyIntegrity(); + } + // reorganise unmapped content for better display + $umapped = $b->getUnMapped(); + foreach( $umapped as $key => $content ) { + $umap[$content['content_name']][$key] = $content; + } + $ret['umap'] = $umap; + return $ret; + } + + function getUnMapped() { + global $gBitSystem; + $ret = NULL; + $sql = "SELECT + lc.`title`, + lc.`content_id`, + lct.`content_name`, ( + SELECT count(*) + FROM `".BIT_DB_PREFIX."liberty_comments` lcom + WHERE lcom.`root_id`=lcom.`parent_id` AND lcom.`root_id`=lc.`content_id` + ) AS thread_count + FROM `".BIT_DB_PREFIX."liberty_content` lc + INNER JOIN `".BIT_DB_PREFIX."liberty_content_types` lct ON (lc.`content_type_guid`=lct.`content_type_guid`) + WHERE lc.`content_id` NOT IN ( + SELECT lc.`content_id` AS content_id + FROM `".BIT_DB_PREFIX."boards` b + INNER JOIN `".BIT_DB_PREFIX."liberty_content` blc ON (blc.`content_id`=b.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."boards_map` map ON (map.`board_content_id`= blc.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lc.`content_id`=map.`topic_content_id`) + ) + AND lc.`content_type_guid` != 'pigeonholes' + AND lc.`content_type_guid` != 'bitboard' + AND lc.`content_type_guid` != 'bitcomment' + AND lc.`title` != '' + ORDER BY lc.`content_type_guid`, lc.`title` + "; + $rs = $this->mDb->query( $sql ); + while( $row = $rs->fetchRow() ) { + $ret[$row['content_id']] = $row; + } + return $ret; + } + + function addContent($content_id) { + if (@BitBase::verifyId($content_id)) { + $data = array( + 'board_content_id'=>$this->mContentId, + 'topic_content_id'=>$content_id, + ); + $this->mDb->associateInsert( BIT_DB_PREFIX."boards_map",$data); + } + } + + function removeContent($content_id) { + if (@BitBase::verifyId($content_id) && @BitBase::verifyId($this->mContentId)) { + $sql = "DELETE FROM `".BIT_DB_PREFIX."boards_map` WHERE `board_content_id` = ? AND `topic_content_id` = ?"; + $result = $this->mDb->query( $sql, array( $this->mContentId,$content_id ) ); + } + } + + function verifyIntegrity() { + global $gBitSystem; + $ret = false; + if( $this->isValid() ) { + $sql = "SELECT + COUNT(*) + FROM `".BIT_DB_PREFIX."boards` b + INNER JOIN `".BIT_DB_PREFIX."boards_map` map ON (map.`board_content_id`= b.`content_id`) + WHERE b.`board_id`=? AND map.`board_content_id` = map.`topic_content_id` + "; + $count = $this->mDb->getOne( $sql, array( $this->mBitBoardId )); + return ($count==1); + } + return $ret; + } + + function fixContentMap() { + if( $this->isValid() && @BitBase::verifyId($this->mContentId)) { + $this->removeContent($this->mContentId); + $this->addContent($this->mContentId); + } + } + + function lookupMapRev($content_id) { + global $gBitDb; + $ret = NULL; + if (@BitBase::verifyId($content_id)) { + $sql = "SELECT `board_content_id` FROM `".BIT_DB_PREFIX."boards_map` map WHERE map.`topic_content_id`=?"; + $ret = $gBitDb->getOne( $sql, array( $content_id )); + } + return $ret; + } + + function getMap() { + global $gBitSystem; + $ret = NULL; + if( $this->isValid() ) { + $sql = "SELECT + lc.`title` AS t_title, + lc.`content_id` AS t_content_id, + lct.`content_name` AS t_content_name, + blc.`title` AS b_title, + blc.`content_id` AS b_content_id, + b.`board_id` AS b_board_id, ( + SELECT count(*) + FROM `".BIT_DB_PREFIX."liberty_comments` lcom + WHERE lcom.`root_id`=lcom.`parent_id` AND lcom.`root_id`=lc.`content_id` + ) AS thread_count, + ((blc.`content_id`- lc.`content_id`)*(blc.`content_id`- lc.`content_id`)) AS order_key + FROM `".BIT_DB_PREFIX."boards` b + INNER JOIN `".BIT_DB_PREFIX."liberty_content` blc ON (blc.`content_id`=b.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."boards_map` map ON (map.`board_content_id`= blc.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lc.`content_id`=map.`topic_content_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content_types` lct ON (lc.`content_type_guid`=lct.`content_type_guid`) + WHERE b.`board_id`=? AND map.`board_content_id`!=map.`topic_content_id` + ORDER BY order_key + "; + $rs = $this->mDb->query( $sql, array( $this->mBitBoardId )); + while( $row = $rs->fetchRow() ) { + $ret[$row['t_content_id']] = $row; + } + } + return $ret; + } + + public static function prepGetList( &$pParamHash ) { + if( empty( $pParamHash['sort_mode'] ) ) { + // default sort_mode for boards is alphabetical + $pParamHash['sort_mode'] = 'title_asc'; + } + LibertyContent::prepGetList( $pParamHash ); + } + + /** + * This function generates a list of records from the liberty_content database for use in a list page + **/ + function getList( &$pParamHash ) { + global $gBitSystem, $gBitUser; + // this makes sure parameters used later on are set + $this->prepGetList( $pParamHash ); + + $selectSql = $joinSql = $whereSql = ''; + $bindVars = array(); + array_push( $bindVars, $this->mContentTypeGuid ); + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + // this will set $find, $sort_mode, $max_records and $offset + extract( $pParamHash ); + + if( is_array( $find ) ) { + // you can use an array of pages + $whereSql .= " AND lc.`title` IN( ".implode( ',',array_fill( 0,count( $find ),'?' ) )." )"; + $bindVars = array_merge ( $bindVars, $find ); + } elseif( is_string( $find ) ) { + // or a string + $whereSql .= " AND UPPER( lc.`title` )like ? "; + $bindVars[] = '%' . strtoupper( $find ). '%'; + } + + $pagination=true; + if (!empty($pParamHash['paginationOff'])) { + $pagination=false; + } + + if (!empty($pParamHash['boards']) && is_array($pParamHash['boards'])) { + $whereSql .= " AND lc.`content_id` IN ( ".implode( ',',array_fill( 0,count( $pParamHash['boards'] ),'?' ) )." )"; + $bindVars = array_merge ( $bindVars, $pParamHash['boards'] ); + } + if (!empty($pParamHash['nboards']) && is_array($pParamHash['nboards'])) { + $whereSql .= " AND lc.`content_id` NOT IN ( ".implode( ',',array_fill( 0,count( $pParamHash['nboards'] ),'?' ) )." )"; + $bindVars = array_merge ( $bindVars, $pParamHash['nboards'] ); + } + + $track = $gBitSystem->isFeatureActive('boards_thread_track'); + $track = true; + if ($track) { + $selectSql .= ", ( + SELECT COUNT(trk.`topic_id`) + FROM `".BIT_DB_PREFIX."boards_map` map + INNER JOIN `".BIT_DB_PREFIX."liberty_comments` lcom ON (map.`topic_content_id` = lcom.`root_id`) + INNER JOIN `".BIT_DB_PREFIX."boards_tracking` trk ON (trk.`topic_id` = lcom.`thread_forward_sequence`) + WHERE lcom.`root_id`=lcom.`parent_id` AND map.`board_content_id`=lc.`content_id` AND trk.`user_id`=".$gBitUser->mUserId." + ) AS track_count "; + + } + + if ($gBitSystem->isFeatureActive('boards_posts_anon_moderation') && !($gBitUser->hasPermission('p_boards_update') || $gBitUser->hasPermission('p_boards_post_update'))) { + + } + if ($gBitSystem->isFeatureActive('boards_posts_anon_moderation') && ($gBitUser->hasPermission('p_boards_update') || $gBitUser->hasPermission('p_boards_post_update'))) { + $selectSql .= ", ( SELECT COUNT(*) + FROM `".BIT_DB_PREFIX."boards_map` map + INNER JOIN `".BIT_DB_PREFIX."liberty_comments` s_lcom ON (map.`topic_content_id` = s_lcom.`root_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` s_lc ON (s_lcom.`content_id` = s_lc.`content_id`) + LEFT JOIN `".BIT_DB_PREFIX."boards_posts` s ON( s_lcom.`comment_id` = s.`comment_id` ) +WHERE map.`board_content_id`=lc.`content_id` AND ((s_lc.`user_id` < 0) AND (s.`is_approved` = 0 OR s.`is_approved` IS NULL) ) + ) AS unreg"; + } else { + $selectSql .= ", 0 AS unreg"; + } + + // always show our own content + $whereSql .= " AND ( lc.`user_id`= ? "; + $bindVars[] = $gBitUser->mUserId; + if( !empty( $pParamHash['content_status_id'] ) ) { + // TODO needs safety checking! - spider + $whereSql .= " OR lc.`content_status_id` = ? "; + $bindVars[] = $pParamHash['content_status_id']; + } elseif( !empty( $pParamHash['min_content_status_id'] ) ) { + $whereSql .= " OR lc.`content_status_id` >= ? "; + $bindVars[] = $pParamHash['min_content_status_id']; + } + $whereSql .= " ) "; + + $query = "SELECT ts.*, lc.`content_id`, lc.`title`, lc.`data`, lc.`format_guid` + $selectSql + FROM `".BIT_DB_PREFIX."boards` ts + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON( lc.`content_id` = ts.`content_id` ) $joinSql + WHERE lc.`content_type_guid` = ? $whereSql + ORDER BY ".$this->mDb->convertSortmode( $sort_mode ); + + $query_cant = "select count(*) + FROM `".BIT_DB_PREFIX."boards` ts INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON( lc.`content_id` = ts.`content_id` ) $joinSql + WHERE lc.`content_type_guid` = ? $whereSql"; + + $result = $this->mDb->query( $query, $bindVars ); + + $ret = array(); + while( $res = $result->fetchRow() ) { + $res['url']= BOARDS_PKG_URL."index.php?b={$res['board_id']}"; + + $res['topic_count'] = $this->mDb->getOne( "SELECT count(*) + FROM `".BIT_DB_PREFIX."boards_map` map + INNER JOIN `".BIT_DB_PREFIX."liberty_comments` lcom ON (map.`topic_content_id` = lcom.`root_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` slc ON( slc.`content_id` = lcom.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."boards_posts` fp ON (fp.`comment_id` = lcom.`comment_id`) + WHERE lcom.`root_id`=lcom.`parent_id` AND map.`board_content_id`=? AND ((fp.`is_approved` = 1) OR (fp.`is_approved` IS NULL))", array( $res['content_id'] ) ); + + $res['post_count'] = $this->mDb->getOne( "SELECT count(*) + FROM `".BIT_DB_PREFIX."liberty_comments` lcom + INNER JOIN `".BIT_DB_PREFIX."liberty_content` slc ON( slc.`content_id` = lcom.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."boards_map` map ON (lcom.`root_id`=map.`topic_content_id`) + LEFT JOIN `".BIT_DB_PREFIX."boards_posts` fp ON (fp.`comment_id` = lcom.`comment_id`) + WHERE map.`board_content_id`=? AND ((fp.`is_approved` = 1) OR (fp.`is_approved` IS NULL))", array( $res['content_id'] ) ); + if($track) { + if ($gBitUser->isRegistered()) { + $res['track']['on'] = true; + $res['track']['count'] = $res['track_count']; + if ($res['post_count']>$res['track_count']) { + $res['track']['mod'] = true; + } else { + $res['track']['mod'] = false; + } + } else { + $res['track']['on'] = false; + } + unset($res['track_count']); + $res['parsed_data'] = LibertyContent::parseDataHash( $res ); + $res['last'] = $this->getLastTopic($res); + } + $ret[] = $res; + } + $pParamHash["cant"] = $this->mDb->getOne( $query_cant, $bindVars ); + + // add all pagination info to pParamHash + LibertyContent::postGetList( $pParamHash ); + return $ret; + } + + function getLastTopic($data) { + global $gBitSystem; + $BIT_DB_PREFIX = BIT_DB_PREFIX; + $query="SELECT slc.`last_modified`, slc.`user_id`, lcom.`anon_name` AS l_anon_name, slc.`title`, lcom.comment_id AS topic_id + FROM `".BIT_DB_PREFIX."boards_map` map + INNER JOIN `".BIT_DB_PREFIX."liberty_comments` lcom ON (map.`topic_content_id` = lcom.`root_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` slc ON( slc.`content_id` = lcom.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."boards_posts` fp ON (fp.`comment_id` = lcom.`comment_id`) + WHERE lcom.`root_id`=lcom.`parent_id` AND map.`board_content_id`=? AND ((fp.`is_approved` IS NULL OR fp.`is_approved` = 1) OR (slc.`user_id` >= 0)) + ORDER BY slc.`last_modified` DESC + "; + $result = $this->mDb->getRow( $query, array( $data['content_id'] ) ); + if (!empty($result['topic_id'])) { + if (empty($result['l_anon_name'])) { + $result['l_anon_name'] = "Anonymous"; + } + $result['topic_id']=intval($result['topic_id']); + $result['url'] = BitBoardTopic::getDisplayUrlFromHash( $result ); + } + return $result; + } + + /** + * Generates the URL to the bitboard page + * @return the link to display the page. + */ + public static function getDisplayUrlFromHash( &$pParamHash ) { + global $gBitSystem; + $ret = NULL; + + if( !empty( $pParamHash['comment'] ) && !empty( $pParamHash['comment']['thread_forward_sequence'] ) ){ + // look up base of comment sequece which is BitBoardTopic + $seq = explode( ".", $pParamHash['comment']['thread_forward_sequence'] ); + $topicRootId = (int)$seq[0]; + if( BitBase::verifyId( $topicRootId )) { + require_once( BOARDS_PKG_CLASS_PATH.'BitBoardTopic.php' ); + $hash = array( 'topic_id' => $topicRootId ); + $ret = BitBoardTopic::getDisplayUrlFromHash( $hash ); + // we're out of here with our topic url + return $ret; + } + } + + if( BitBase::verifyId( $pParamHash['board_id'] )) { + if( $gBitSystem->isFeatureActive( 'pretty_urls' ) || $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ) { + $rewrite_tag = $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ? 'view/':''; + $ret = BOARDS_PKG_URL.$rewrite_tag.'board/'.$pParamHash['board_id']; + } else { + $ret = BOARDS_PKG_URL."index.php?b=".$pParamHash['board_id']; + } + } else { + $ret = parent::getDisplayUrlFromHash( $pParamHash ); + } + + return $ret; + } + + function getBoardSelectList( $pBlankFirst=FALSE ) { + global $gBitSystem, $gBitUser; + + // invoke list sql principly to enforce permission services + $selectSql = $joinSql = $whereSql = ''; + $bindVars = array(); + + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + /* DEPRECATED - has some pointless stuff + $query = "SELECT lc.`content_id` as hash_key, lc.`title` AS `title` + FROM `".BIT_DB_PREFIX."boards` b + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON( lc.`content_id` = b.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."boards_map` bm ON( bm.`board_content_id`=b.`content_id` ) + LEFT JOIN `".BIT_DB_PREFIX."liberty_comments` lcom ON (bm.`topic_content_id` = lcom.`root_id`) + GROUP BY lc.`content_id`, lc.`title`, lcom.`comment_id` + ORDER BY lc.`title` ASC"; + */ + + // replacement query where we at least check that the board has been mapped to another board - a requirement for displaying comments + // if you hate it fix it or lets chat -wjames5 + $query = "SELECT lc.`content_id` as hash_key, lc.`title` AS `title` + FROM `".BIT_DB_PREFIX."boards` b + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON( lc.`content_id` = b.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."boards_map` bm ON( bm.`topic_content_id`=b.`content_id` ) + $joinSql + WHERE lc.`content_id` = b.`content_id` $whereSql + ORDER BY lc.`title` ASC"; + + $ret = array(); + + if( $rslt = $this->mDb->query( $query, $bindVars ) ){ + if( $pBlankFirst ) { + $ret[''] = '---------'; + } + while( $row = $rslt->fetchRow() ) { + $ret[$row['hash_key']] = $row['title']; + } + } + + return $ret; + } + + function getBoard( $contentId ) { + global $gBitDb; + global $gBitUser; + //var_dump($GLOBALS); + if( LibertyContent::verifyId( $contentId ) ) { + // LibertyContent::load()assumes you have joined already, and will not execute any sql! + // This is a significant performance optimization + $bindVars = array(); + $selectSql = $joinSql = $whereSql = ''; + array_push( $bindVars, $contentId ); + $gBitUser->getServicesSql( 'content_load_sql_function', $selectSql, $joinSql, $whereSql, $bindVars ); + + $query = "SELECT lc.*, uue.`login` AS modifier_user, uue.`real_name` AS modifier_real_name, uuc.`login` AS creator_user, uuc.`real_name` AS creator_real_name $selectSql + FROM `".BIT_DB_PREFIX."liberty_content` lc $joinSql + LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON( uue.`user_id` = lc.`modifier_user_id` ) + LEFT JOIN `".BIT_DB_PREFIX."users_users` uuc ON( uuc.`user_id` = lc.`user_id` ) + WHERE lc.`content_id`=? $whereSql"; + $result = $gBitDb->query( $query, $bindVars ); + + $ret = array(); + if( $result && $result->numRows() ) { + $ret = $result->fields; + + $ret['creator'] =( isset( $result->fields['creator_real_name'] )? $result->fields['creator_real_name'] : $result->fields['creator_user'] ); + $ret['editor'] =( isset( $result->fields['modifier_real_name'] )? $result->fields['modifier_real_name'] : $result->fields['modifier_user'] ); + $ret['display_url'] = BIT_ROOT_URL."index.php?content_id=$contentId"; + } + } + return( $ret ); + } + + public static function getLinkedBoard( $pContentId ) { + global $gBitDb; + $ret = NULL; + if( BitBase::verifyId( $pContentId ) ) { + $sql = "SELECT b.`board_id`, b.`content_id` AS `board_content_id`, COUNT(lcom.`comment_id`) AS `post_count` + FROM `".BIT_DB_PREFIX."boards_map` bm + INNER JOIN `".BIT_DB_PREFIX."boards` b ON (bm.`board_content_id`=b.`content_id`) + LEFT JOIN `".BIT_DB_PREFIX."liberty_comments` lcom ON (lcom.`root_id`=bm.`topic_content_id`) + WHERE bm.`topic_content_id`=? + GROUP BY b.`board_id`, b.`content_id`"; + $ret = $gBitDb->getRow( $sql, array( $pContentId ) ); + } + return $ret; + } + + + // =-=-=-=-=-=-=-=-=-=-=-=-=-= Board Sync Methods =-=-=-=-=-=-=-=-=-=-=-=-=-= + function getBoardSyncInbox() { + global $gBitSystem; + $ret = ''; + if( $gBitSystem->getConfig('boards_sync_user') ) { + $ret = $gBitSystem->getConfig('boards_sync_user').'@'.$gBitSystem->getConfig('boards_sync_mail_server'); + } + return $ret; + } + + function getBoardMailingList() { + global $gBitSystem; + $ret = NULL; + if( $this->isValid() && $gBitSystem->getConfig( 'boards_sync_mail_server' ) && $this->getPreference( 'boards_mailing_list' ) ) { + $ret = $this->getPreference( 'boards_mailing_list' ).'@'.$gBitSystem->getConfig( 'boards_email_host', $gBitSystem->getConfig( 'kernel_server_name' ) ); + } + return $ret; + } +} + +function boards_content_display ( $pContent ) { + global $gBitSmarty; + if( $pContent->isValid() && $pContent->getField('content_type_guid') != 'bitboard' ) { + $gBitSmarty->assign( 'boardInfo', BitBoard::getLinkedBoard( $pContent->mContentId ) ); + } +} + +function boards_content_edit ( $pContent, $pParamHash ) { + global $gBitSmarty; + // topic service + if( !$pContent->isContentType( BITBOARDTOPIC_CONTENT_TYPE_GUID ) ) { + if( $pContent->isValid() ) { + $gBitSmarty->assign( 'boardInfo', BitBoard::getLinkedBoard( $pContent->mContentId ) ); + } else { + $boardInfo['board_content_id'] = $pParamHash['linked_board_cid']; + $gBitSmarty->assign( 'boardInfo', $boardInfo ); + } + require_once( BOARDS_PKG_CLASS_PATH.'BitBoard.php' ); + $board = new BitBoard(); + $boardList = $board->getBoardSelectList( TRUE ); + $gBitSmarty->assign( 'boardList', $boardList ); + } +} + +// store services for boads +function boards_content_store( $pContent, $pParamHash ) { + global $gBitDb, $gBitSmarty, $gBitSystem; + + require_once( BOARDS_PKG_CLASS_PATH.'BitBoardTopic.php' ); + // do not allow unassigning topics. the UI should prevent this, but just to make sure... + if( $pContent->isValid() && !$pContent->isContentType( BITBOARDTOPIC_CONTENT_TYPE_GUID ) && !$pContent->isContentType( BITBOARD_CONTENT_TYPE_GUID ) ) { + // wipe out all previous assignments for good measure. Not the sanest thing to do, but edits are infrequent - at least for now + if ($gBitSystem->isFeatureActive('boards_link_by_pigeonholes') && $gBitSystem->isPackageActive('pigeonholes')) { + // Delete all old mappings + $pContent->mDb->query( "DELETE FROM `".BIT_DB_PREFIX."boards_map` WHERE `topic_content_id`=?", array( $pContent->mContentId ) ); + + // Get the pigeonholes this content is in + $p = null; + if ( ! empty( $pParamHash['pigoneholes'] ) ) { + foreach( $pParamHash['pigeonholes']['pigeonhole'] as $p_id ) { + require_once(PIGEONHOLES_PKG_PATH.'Pigeonholes.php'); + if (empty($p)) { + $p = new Pigeonholes(); + } + + // What boards are in the same pigeonhole? + $params = + array('content_type_guid' => BITBOARD_CONTENT_TYPE_GUID, + 'content_id' => $p_id ); + $boards = $p->getMemberList( $params ); + + // Insert into these boards + foreach ($boards as $board) { + if( @BitBase::verifyId( $board['content_id'] ) ) { + $pContent->mDb->query( "INSERT INTO `".BIT_DB_PREFIX."boards_map` (`board_content_id`,`topic_content_id`) VALUES (?,?)", array( $board['content_id'], $pContent->mContentId ) ); + } + } + } + } + } + else { + $pContent->mDb->query( "DELETE FROM `".BIT_DB_PREFIX."boards_map` WHERE `topic_content_id`=?", array( $pContent->mContentId ) ); + if( @BitBase::verifyId( $pParamHash['linked_board_cid'] ) ) { + $pContent->mDb->query( "INSERT INTO `".BIT_DB_PREFIX."boards_map` (`board_content_id`,`topic_content_id`) VALUES (?,?)", array( $pParamHash['linked_board_cid'], $pContent->mContentId ) ); + } + } + $gBitSmarty->assign( 'boardInfo', BitBoard::getLinkedBoard( $pContent->mContentId ) ); + } else { + if( @BitBase::verifyId( $pParamHash['content_id'] ) && @BitBase::verifyId( $pParamHash['linked_board_cid'] ) ) { + $pContent->mDb->query( "INSERT INTO `".BIT_DB_PREFIX."boards_map` (`board_content_id`,`topic_content_id`) VALUES (?,?)", array( $pParamHash['linked_board_cid'], $pParamHash['content_id'] ) ); + } + } +} + +// store services for topics and posts +function boards_comment_store( &$pObject, &$pParamHash ) { + global $gBitSystem; + // board posts ( e.g. liberty comments ) service + // @TODO check that root object is a board -- otherwise all comments get fired + // @TODO probably should migrate sendNotification to Switchboard + + if( $gBitSystem->isPackageActive( 'boards' ) && $pObject->isContentType( BITCOMMENT_CONTENT_TYPE_GUID ) && $gBitSystem->isFeatureActive( 'boards_thread_notification' )) { + if( isset( $pObject->mInfo['thread_forward_sequence'] ) ){ + $topic_id = substr( $pObject->mInfo['thread_forward_sequence'], 0, 10 ); + $data = BitBoardTopic::getNotificationData($topic_id); + foreach( $data['users'] as $login => $user ) { + if( $data['topic']->mInfo['llc_last_modified'] > $user['track_date'] && $data['topic']->mInfo['llc_last_modified'] > $user['track_notify_date'] ) { + $data['topic']->sendNotification( $user ); + } + } + } + } +} + +function boards_content_verify( &$pObject, &$pParamHash ){ + // board posts ( e.g. liberty comments ) service + global $gBitSystem, $gBitUser; + // use is_a instead of isContentType( BITCOMMENT_CONTENT_TYPE_GUID ) as isContentType() checks isValid(), and this service method will not properly handle new object stores + if( $gBitSystem->isPackageActive( 'boards' ) && is_a( $pObject , 'LibertyComment' ) ) { + if( BitBoardTopic::isLockedMsg( $pParamHash['parent_id'] )) { + $pObject->mErrors['warning']=tra("The selected Topic is Locked posting is disabled"); + } + } +} + +function boards_content_expunge( $pContent ) { + global $gBitSmarty; + if( $pContent->isValid() ) { + $pContent->mDb->query( "DELETE FROM `".BIT_DB_PREFIX."boards_map` WHERE `topic_content_id`=?", array( $pContent->mContentId ) ); + } +} + +?> diff --git a/includes/classes/BitBoardPost.php b/includes/classes/BitBoardPost.php new file mode 100644 index 0000000..1043897 --- /dev/null +++ b/includes/classes/BitBoardPost.php @@ -0,0 +1,468 @@ +<?php +/** + * $Header$ + * $Id$ + * + * Messageboards class to illustrate best practices when creating a new bitweaver package that + * builds on core bitweaver functionality, such as the Liberty CMS engine + * + * @author spider <spider@steelsun.com> + * @version $Revision$ + * @package boards + */ + +/** + * required setup + */ +require_once( LIBERTY_PKG_PATH.'LibertyMime.php' ); +require_once( BOARDS_PKG_CLASS_PATH.'BitBoardTopic.php' ); + +/** + * @package boards + */ +class BitBoardPost extends LibertyComment { + /** + * During initialisation, be sure to call our base constructors + */ + function __construct($pCommentId = NULL, $pContentId = NULL, $pInfo = NULL) { + parent::__construct($pCommentId,$pContentId,$pInfo); + + // Permission setup + $this->mViewContentPerm = 'p_boards_read'; + $this->mUpdateContentPerm = 'p_boards_post_update'; + $this->mAdminContentPerm = 'p_boards_admin'; + } + + /** + * This function verifies the data for a post + */ + function verify( &$pParamHash ) { + if( isset( $pParamHash['is_approved'] ) ) { + if( !is_numeric( $pParamHash['is_approved'] ) || $pParamHash['is_approved'] > 1 || $pParamHash['is_approved'] < 0 ) { + $this->mErrors[]=("Invalid post approved state"); + } else { + $pParamHash['post_store']['is_approved'] = $pParamHash['is_approved']; + } + } + if( isset( $pParamHash['is_warned'] ) ) { + if( !is_numeric( $pParamHash['warned'] ) || $pParamHash['is_warned'] > 1 || $pParamHash['is_warned'] < 0 ) { + $this->mErrors[]=("Invalid warned state"); + } else { + $pParamHash['post_store']['is_warned'] = $pParamHash['is_warned']; + } + } + if( !empty( $pParamHash['warned_message'] ) ) { + $pParamHash['post_store']['warned_message'] = $pParamHash['warned_message']; + } + if( !empty( $pParamHash['warned_message'] ) ) { + $pParamHash['post_store']['warned_message'] = $pParamHash['warned_message']; + } + if( !empty( $pParamHash['migrate_post_id'] ) ) { + $pParamHash['post_store']['migrate_post_id'] = $pParamHash['migrate_post_id']; + } + + return( count( $this->mErrors ) == 0 && !empty( $pParamHash['post_store'] ) ); + } + + /** + * This function stores a post + */ + function store( &$pParamHash ) { + global $gBitSystem; + $ret = FALSE; + if( $this->mCommentId && $this->verify( $pParamHash ) ) { + //$gBitSystem->verifyPermission('p_boards_update'); + //$pParamHash = (($pParamHash + 1)%2); + $query_sel = "SELECT * FROM `".BIT_DB_PREFIX."boards_posts` WHERE `comment_id` = ?"; + $isStored = $this->mDb->getOne( $query_sel, array( $this->mCommentId ) ); + if( $isStored ) { + $result = $this->mDb->associateUpdate( 'boards_posts', $pParamHash['post_store'], array( 'comment_id' => $this->mCommentId ) ); + } else { + $pParamHash['post_store']['comment_id'] = $this->mCommentId; + $result = $this->mDb->associateInsert( 'boards_posts', $pParamHash['post_store'] ); + } + $ret = TRUE; + } + return $ret; + } + + /** + * This function gets the meta data relating to a post + */ + function loadMetaData() { + if ($this->isValid()) { + if (!isset($this->mInfo['accepted'])) { + $key = array('comment_id' => $this->mCommentId); + $query_sel = "SELECT + post.is_approved, + post.is_warned, + post.warned_message + FROM `".BIT_DB_PREFIX."boards_posts` post WHERE comment_id=?"; + $data = $this->mDb->getRow( $query_sel , array_values($key)); + if ($data) { + if (!empty($data['warned_message'])) { + $data['warned_message'] = str_replace("\n","<br />\n",$data['warned_message']); + } + $this->mInfo=array_merge($this->mInfo,$data); + } + } + } + } + + /** + * This function removes a bitboard entry + **/ + function expunge() { + $ret = FALSE; + if( $this->isValid() ) { + $this->StartTrans(); + // parent actually has deletion of rows in boards for constraint reasons + if( parent::expunge() ) { + $this->CompleteTrans(); + $ret = TRUE; + } else { + $this->mDb->RollbackTrans(); + } + } + return $ret; + } + + /** + * This function gets all the post relating to a topic + */ + function getComments( $pContentId = NULL, $pMaxComments = NULL, $pOffset = NULL, $pSortOrder = NULL, $pDisplayMode = NULL ) { + global $gBitUser, $gBitSystem; + + $joinSql = $selectSql = $whereSql = ''; + + $ret = array(); + $contentId = $this->mCommentId; + + $mid = 'thread_forward_sequence ASC'; + if (!empty($pSortOrder)) { + if ($pSortOrder == 'commentDate_desc') { + $mid = 'created DESC'; + } else if ($pSortOrder == 'commentDate_asc') { + $mid = 'created ASC'; + } elseif ($pSortOrder == 'thread_asc') { + $mid = 'thread_forward_sequence ASC'; + // thread newest first is harder... + } elseif ($pSortOrder == 'thread_desc') { + $mid = 'thread_reverse_sequence ASC'; + } else { + $mid = $this->mDb->convertSortmode( $pSortOrder ); + } + } + $mid = 'order by ' . $mid; + + $bindVars = array(); + if (is_array( $contentId ) ) { + $mid2 = 'in ('.implode(',', array_fill(0, count( $pContentId ), '?')).')'; + $bindVars = $contentId; + $select1 = ', lcp.content_type_guid as parent_content_type_guid, lcp.title as parent_title '; + $join1 = " LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content` lcp ON (lcp.content_id = lcom.parent_id) "; + } elseif ($contentId) { + $mid2 = "lcom.`thread_forward_sequence` LIKE '".sprintf("%09d.",$contentId)."%'"; + $select1 = ''; + $join1 = ''; + } + + if ($gBitSystem->isFeatureActive('boards_posts_anon_moderation') && !($gBitUser->hasPermission('p_boards_update') || $gBitUser->hasPermission('p_boards_post_update'))) { + $whereSql .= " AND ((post.`is_approved` = 1) OR (lc.`user_id` >= 0))"; + } + + $pListHash = array( 'content_id' => $contentId, 'max_records' => $pMaxComments, 'offset'=>$pOffset, 'sort_mode'=> $pSortOrder, 'display_mode' => $pDisplayMode, 'has_comment_view_perm' => TRUE ); + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars, $this, $pListHash ); + + if ($pContentId) { + $sql = "SELECT lcom.`comment_id`, lcom.`parent_id`, lcom.`root_id`, + lcom.`thread_forward_sequence`, lcom.`thread_reverse_sequence`, lcom.`anon_name`, lc.*, uu.`email`, uu.`real_name`, uu.`login`, + post.is_approved, + post.is_warned, + post.warned_message, + uu.registration_date AS registration_date, + tf_ava.`file_name` AS `avatar_file_name`, tf_ava.`mime_type` AS `avatar_mime_type`, tf_ava.`user_id` AS `avatar_user_id`, ta_ava.`attachment_id` AS `avatar_attachment_id` + $selectSql $select1 + FROM `".BIT_DB_PREFIX."liberty_comments` lcom + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lcom.`content_id` = lc.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON (lc.`user_id` = uu.`user_id`) + $joinSql $join1 + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_attachments` ta_ava ON ( uu.`avatar_attachment_id`=ta_ava.`attachment_id` ) + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_files` tf_ava ON ( tf_ava.`file_id`=ta_ava.`foreign_id` ) + LEFT JOIN `".BIT_DB_PREFIX."boards_posts` post ON (post.`comment_id` = lcom.`comment_id`) + WHERE $mid2 $whereSql $mid"; + + $flat_comments = array(); + + if( $result = $this->mDb->query( $sql, $bindVars, $pMaxComments, $pOffset ) ) { + while( $row = $result->FetchRow() ) { + if (empty($row['anon_name'])) { + $row['anon_name'] = "Anonymous"; + } + if( $row['avatar_file_name'] ) { + $row['user_avatar_url'] = liberty_fetch_thumbnail_url( array( + 'source_file' => liberty_mime_get_source_file( array( 'user_id'=>$row['avatar_user_id'], 'file_name'=>$row['avatar_file_name'], 'mime_type'=>$row['avatar_mime_type'], 'attachment_id'=>$row['avatar_attachment_id'] ) ), + 'size' => 'avatar' + )); + } else { + $row['user_avatar_url'] = FALSE; + } + if (!empty($row['warned_message'])) { + $row['warned_message'] = str_replace("\n","<br />\n",$row['warned_message']); + } + $row['data'] = trim( $row['data'] ); + $row['user_url'] = BitUser::getDisplayUrlFromHash( $row ); + $row['parsed_data'] = self::parseDataHash( $row ); + $row['level'] = substr_count ( $row['thread_forward_sequence'], '.' ) - 1; + $c = new LibertyComment(); + $c->mInfo=$row; + $row['is_editable'] = $c->userCanEdit(); + + if( $gBitSystem->isFeatureActive( 'comments_allow_attachments' ) ){ + // get attachments for each comment + global $gLibertySystem; + $query = "SELECT * FROM `".BIT_DB_PREFIX."liberty_attachments` la WHERE la.`content_id`=? ORDER BY la.`pos` ASC, la.`attachment_id` ASC"; + if( $result2 = $this->mDb->query( $query,array( (int)$row['content_id'] ))) { + while( $row2 = $result2->fetchRow() ) { + if( $func = $gLibertySystem->getPluginFunction( $row2['attachment_plugin_guid'], 'load_function', 'mime' )) { + // we will pass the preferences by reference that the plugin can easily update them + if( empty( $row['storage'][$row2['attachment_id']] )) { + $row['storage'][$row2['attachment_id']] = array(); + } + $row['storage'][$row2['attachment_id']] = $func( $row2, $row['storage'][$row2['attachment_id']] ); + } else { + print "No load_function for ".$row2['attachment_plugin_guid']; + } + } + } + // end get attachements for each comment + } + + $flat_comments[$row['content_id']] = $row; + // vd($row); + } + } + + # now select comments wanted + $ret = $flat_comments; + + } + return $ret; + } + + /** + * This function gets a list of posts + */ + function getList( &$pListHash ) { + global $gBitUser, $gBitSystem; + + $this->prepGetList( $pListHash ); + + $joinSql = $selectSql = $whereSql = ''; + + $ret = array(); + $contentId = $this->mCommentId; + +// $mid = 'ORDER BY `thread_forward_sequence` ASC'; + + $bindVars = array(); + if( !empty( $pListHash['content_id'] ) ) { + if (is_array( $contentId ) ) { + $mid2 = 'in ('.implode(',', array_fill(0, count( $pListHash['content_id'] ), '?')).')'; + $bindVars = $contentId; + $selectSql = ', lcp.content_type_guid as parent_content_type_guid, lcp.title as parent_title '; + $joinSql .= " LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_content` lcp ON (lcp.content_id = lcom.parent_id) "; + } elseif( is_numeric( $contentId ) ) { + $whereSql .= " AND `thread_forward_sequence` LIKE '".sprintf("%09d.",$contentId)."%'"; + } + } + + if ($gBitSystem->isFeatureActive('boards_posts_anon_moderation') && !($gBitUser->hasPermission('p_boards_update') || $gBitUser->hasPermission('p_boards_post_update'))) { + $whereSql .= " AND ((post.`is_approved` = 1) OR (lc.`user_id` >= 0))"; + } + + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars, $this ); + + if( BitBase::verifyIdParameter( $pListHash, 'board_id' ) ) { + $joinSql .= "INNER JOIN `".BIT_DB_PREFIX."boards` b ON (b.`content_id` = bm.`board_content_id`)"; + $whereSql .= ' AND b.`board_id`=? '; + array_push( $bindVars, (int)$pListHash['board_id'] ); + } + + if( BitBase::verifyId( $pListHash['user_id'] ) ) { + $whereSql .= ' AND lc.`user_id`=? '; + array_push( $bindVars, $pListHash['user_id'] ); + } + + if( !empty( $whereSql ) ) { + $whereSql = preg_replace( '/^[\s]*AND\b/i', 'WHERE ', $whereSql ); + } + + $sql = "SELECT lcom.`comment_id`, lcom.`parent_id`, lcom.`root_id`, lcom.`thread_forward_sequence`, lcom.`thread_reverse_sequence`, lcom.`anon_name`, lc.*, uu.`email`, uu.`real_name`, uu.`login`, post.is_approved, post.is_warned, post.warned_message, uu.registration_date AS registration_date, + tf_ava.`file_name` AS `avatar_file_name`, tf_ava.`mime_type` AS `avatar_mime_type`, tf_ava.`user_id` AS `avatar_user_id`, ta_ava.`attachment_id` AS `avatar_attachment_id` + $selectSql + FROM `".BIT_DB_PREFIX."liberty_comments` lcom + INNER JOIN `".BIT_DB_PREFIX."boards_map` bm ON (lcom.`root_id` = bm.`topic_content_id`) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lcom.`content_id` = lc.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON (lc.`user_id` = uu.`user_id`) + $joinSql + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_attachments` ta_ava ON ( uu.`avatar_attachment_id`=ta_ava.`attachment_id` ) + LEFT OUTER JOIN `".BIT_DB_PREFIX."liberty_files` tf_ava ON ( tf_ava.`file_id`=ta_ava.`foreign_id` ) + LEFT JOIN `".BIT_DB_PREFIX."boards_posts` post ON (post.`comment_id` = lcom.`comment_id`) + $whereSql ORDER BY ".$this->mDb->convertSortmode( $pListHash['sort_mode'] ); + + $ret = array(); + + if( $result = $this->mDb->query( $sql, $bindVars, $pListHash['max_records'], $pListHash['offset'] ) ) { + while( $row = $result->FetchRow() ) { + if (empty($row['anon_name'])) $row['anon_name'] = "Anonymous"; + if( !empty( $row['avatar_file_name'] )) { + $row['user_avatar_url'] = liberty_fetch_thumbnail_url( array( + 'source_file' => liberty_mime_get_source_file( array( 'user_id'=>$row['avatar_user_id'], 'file_name'=>$row['avatar_file_name'], 'mime_type'=>$row['avatar_mime_type'], 'attachment_id'=>$row['avatar_attachment_id'] ) ), + 'size' => 'avatar' + )); + } else { + $row['user_avatar_url'] = FALSE; + } + unset($row['avatar_file_name']); + if (!empty($row['warned_message'])) { + $row['warned_message'] = str_replace("\n","<br />\n",$row['warned_message']); + } + $row['data'] = trim($row['data']); + $row['user_url']=BitUser::getDisplayUrlFromHash($row); + $row['parsed_data'] = self::parseDataHash( $row ); + $row['level'] = substr_count ( $row['thread_forward_sequence'], '.' ) - 1; + $row['topic_id'] = boards_get_topic_comment( $row['thread_forward_sequence'] ); + $row['display_url'] = static::getDisplayUrlFromHash( $row ); + $c = new LibertyComment(); + $c->mInfo=$row; + $row['is_editable'] = $c->userCanEdit(); + $ret[] = $row; + //va($row); + } + } + + return $ret; + } + + /** + * This function counts the posts relating to a topic + */ + function getNumComments($pContentId = NULL) { + $ret = 0; + + $contentId = $this->mCommentId; + + $bindVars = array(); + + $joinSql = $selectSql = $whereSql = ''; + $paramHash = array( 'include_comments' => TRUE ); + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars, $this, $paramHash ); + + if ($pContentId) { + $sql = "SELECT COUNT(*) + FROM `".BIT_DB_PREFIX."liberty_comments` lcom + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lcom.`content_id` = lc.`content_id`) + INNER JOIN `".BIT_DB_PREFIX."users_users` uu ON (lc.`user_id` = uu.`user_id`) $joinSql + LEFT JOIN `".BIT_DB_PREFIX."boards_posts` post ON (post.`comment_id` = lcom.`comment_id`) + WHERE lcom.`thread_forward_sequence` LIKE '".sprintf("%09d.",$contentId)."%' $whereSql + "; + $ret = $this->mDb->getOne( $sql, $bindVars ); + } + return $ret; + } + + /** + * This function generates a valid lookup URL + */ + function getDisplayUrl() { + $ret = NULL; + if( $this->isValid() ) { + $urlHash['comment_id'] = $this->mCommentId; + $urlHash['topic_id'] = $this->getTopicId(); + $ret = static::getDisplayUrlFromHash( $urlHash ); + } + return $ret; + } + + /** + * Generates the URL to the bitboard page + * @return the link to display the page. + */ + public static function getDisplayUrlFromHash( &$pParamHash ) { + global $gBitSystem; + + $ret = NULL; + if( static::verifyId( $pParamHash['comment_id'] ) ) { + if( $gBitSystem->isFeatureActive( 'pretty_urls' ) || $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ) { + $rewrite_tag = $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ? 'view/' : ''; + $ret = BOARDS_PKG_URL.$rewrite_tag."topic/".$pParamHash['topic_id']; + } else { + $ret = BOARDS_PKG_URL."index.php?t=".$pParamHash['topic_id']; + } + + if( $pParamHash['comment_id'] != $pParamHash['topic_id'] ) { + $ret .= '#comment_'.$pParamHash['comment_id']; + } + } + return $ret; + } + + function getTopicId() { + return boards_get_topic_comment( $this->getField( 'thread_forward_sequence') ); + } + + function modApprove() { + $data['is_approved'] = 1; + $this->setMetaData($data); + } + + function modReject() { + $this->deleteComment(); + } + + function modWarn($message) { + global $gBitSystem, $gBitUser; + + if (empty($message)) { + $gBitSystem->fatalError("No Warning Message Given. <br />A post cannot be warned without a message"); + } + $data['is_warned']=1; + $data['warned_message']=$message; + $this->setMetaData($data); + + if ($gBitSystem->isPackageActive('messages')) { + require_once(MESSAGES_PKG_PATH.'Messages.php'); + + $u = new BitUser($this->mInfo['user_id']); + $u->load(); + $userInfo = $u->mInfo; + + $pm = new Messages(); + $message = "Your post \"".$this->mInfo['title']."\" [http://".$_SERVER['HTTP_HOST'].$this->getContactUrl()."] has been warned with the following message:\n$message\n"; + $msgHash = array( + 'to_login' => $userInfo['login'], + 'to' => $userInfo['real_name'], + 'subject' => tra( 'Warned Post' ).': '.$this->mInfo['title'], + 'priority' => 4, + ); + $pm->postMessage( $msgHash ); + } + } + + function setMetaData($data) { + if ($this->isValid()) { + $key = array('comment_id' => $this->mCommentId); + $query_sel = "SELECT COUNT(*) FROM `".BIT_DB_PREFIX."boards_posts` WHERE comment_id=?"; + $c = $this->mDb->getOne( $query_sel , array_values($key)); + if ($c == 0) { + $data=array_merge($data,$key); + $this->mDb->associateInsert(BIT_DB_PREFIX."boards_posts",$data); + } else { + + $this->mDb->associateUpdate(BIT_DB_PREFIX."boards_posts",$data,$key); + } + } + } +} +?> diff --git a/includes/classes/BitBoardTopic.php b/includes/classes/BitBoardTopic.php new file mode 100644 index 0000000..1b1235d --- /dev/null +++ b/includes/classes/BitBoardTopic.php @@ -0,0 +1,778 @@ +<?php +/** + * $Header$ + * $Id$ + * + * Messageboards class to illustrate best practices when creating a new bitweaver package that + * builds on core bitweaver functionality, such as the Liberty CMS engine + * + * @author spider <spider@steelsun.com> + * @version $Revision$ + * @package boards + */ + +/** + * required setup + */ +require_once( LIBERTY_PKG_PATH.'LibertyComment.php' ); +require_once( BOARDS_PKG_CLASS_PATH.'BitBoardPost.php' ); + +/** +* This is used to uniquely identify the object +*/ +define( 'BITBOARDTOPIC_CONTENT_TYPE_GUID', 'bitboardtopic' ); + +/** + * expunge is handled explicitly in LibertyComment::expunge + * @package boards + */ +class BitBoardTopic extends LibertyMime { + /** + * Primary key for our mythical Messageboards class object & table + * @public + */ + public $mRootId; + + /** + * the content id of the topic comment object + * this is really the contentId, but mContentId houses the parent board content_id currently + **/ + public $mCommentContentId; + + /** + * During initialisation, be sure to call our base constructors + **/ + function __construct( $pRootId=NULL ) { + parent::__construct(); + $this->mRootId = (int)$pRootId; + + // Permission setup + $this->mViewContentPerm = 'p_boards_read'; + $this->mUpdateContentPerm = 'p_boards_update'; + $this->mAdminContentPerm = 'p_boards_admin'; + + $this->mRootObj = NULL; //a reference to the root obj + } + + /** + * Load the data from the database + * @param pParamHash be sure to pass by reference in case we need to make modifcations to the hash + **/ + function load( $pContentId = NULL, $pPluginParams = NULL ) { + global $gBitUser, $gBitSystem; + if( $this->verifyId( $this->mRootId ) || $this->verifyId( $this->mContentId ) ) { + // This is a significant performance optimization + $lookupColumn = $this->verifyId( $this->mRootId ) ? 'lcom.`comment_id`' : 'lc.`content_id`'; + $bindVars = array(); + $selectSql = $joinSql = $whereSql = ''; + array_push( $bindVars, $lookupId = @BitBase::verifyId( $this->mRootId ) ? $this->mRootId : $this->mContentId ); + $paramHash = array( array( 'include_comments' => TRUE ) ); + $this->getServicesSql( 'content_load_sql_function', $selectSql, $joinSql, $whereSql, $bindVars, $this, $paramHash ); + + if (!($gBitUser->hasPermission('p_boards_update') || $gBitUser->hasPermission('p_boards_posts_update'))) { + //$whereSql .= " AND ((first.`is_approved` = 1) OR (flc.`user_id` >= 0))"; + } + + BitBoardTopic::loadTrack($selectSql, $joinSql); + + $BIT_DB_PREFIX = BIT_DB_PREFIX; + $query =" + SELECT + lc.`user_id` AS flc_user_id, + lc.`created` AS flc_created, + lc.`last_modified` AS flc_last_modified, + lc.`title` AS title, + lc.`content_id` AS flc_content_id, + + COALESCE(post.`is_approved`,0) AS first_approved, + lcom.`anon_name`, + + th.`parent_id` AS th_first_id, + COALESCE(th.`is_locked`,0) AS th_is_locked, + COALESCE(th.`is_moved`,0) AS th_is_moved, + COALESCE(th.`is_sticky`,0) AS th_is_sticky, + + lcom.`comment_id` AS th_thread_id, + lcom.`root_id` AS th_root_id, + lcom.`root_id` AS content_id, + lc.`content_type_guid` AS content_type_guid, + + rlc.content_id AS root_content_id, rlc.title AS root_title, rlc.content_type_guid AS `root_content_type_guid`, + + map.`board_content_id` AS board_content_id, b.`board_id` + + $selectSql + FROM `".BIT_DB_PREFIX."liberty_comments` lcom + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON( lc.`content_id` = lcom.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."boards_map` map ON (map.`topic_content_id`=lcom.`root_id` ) + INNER JOIN `".BIT_DB_PREFIX."boards` b ON (map.`board_content_id`=b.`content_id` ) + INNER JOIN `".BIT_DB_PREFIX."liberty_content` rlc ON (rlc.`content_id` = lcom.`root_id`) + $joinSql + LEFT JOIN `".BIT_DB_PREFIX."boards_topics` th ON (th.`parent_id`=lcom.`content_id`) + LEFT JOIN `".BIT_DB_PREFIX."boards_posts` post ON(post.`comment_id`=lcom.`comment_id`) + WHERE + lcom.`root_id`=lcom.`parent_id` AND $lookupColumn=? + $whereSql"; + + $result = $this->mDb->query( $query, $bindVars ); + + if( $result && $result->numRows() ) { + $this->mInfo = $result->fields; + $this->mContentId = $this->getField( 'content_id' ); + $this->mCommentContentId = $this->getField('flc_content_id'); + $llc_data = BitBoardTopic::getLastPost($this->mInfo); + $this->mInfo = array_merge($this->mInfo,$llc_data); + $this->mRootId = $result->fields['th_thread_id']; + // @TODO this would make more sense if this were assigned to mRootId - but that is currently in use as top comment id + $this->mInfo['root_id'] = $result->fields['th_root_id']; + BitBoardTopic::track($this->mInfo); + $this->mInfo['display_url'] = $this->getDisplayUrl(); + + if (empty($this->mInfo['anon_name'])) { + $this->mInfo['anon_name'] = "Anonymous"; + } + + parent::load(); // assumes you have joined already, and will not execute any sql! + } + } + return( count( $this->mInfo ) ); + } + + function lookupByMigratePost( $pMigratePostId ) { + global $gBitDb; + $ret = NULL; + if( BitBase::verifyId( $pMigratePostId ) ) { + $path = $gBitDb->getOne( "SELECT lcom.`thread_forward_sequence` FROM `".BIT_DB_PREFIX."boards_posts` bp INNER JOIN `".BIT_DB_PREFIX."liberty_comments` lcom ON(bp.`comment_id`=lcom.`comment_id`) WHERE bp.`migrate_post_id`=?", array( $pMigratePostId ) ); + if( $path ) { + $ret = boards_get_topic_comment( $path ); + } + } + return $ret; + } + + function lookupByMigrateTopic( $pMigrateTopicId ) { + global $gBitDb; + $ret = NULL; + if( BitBase::verifyId( $pMigrateTopicId ) ) { + $ret = $gBitDb->getOne( "SELECT lcom.`comment_id` FROM `".BIT_DB_PREFIX."boards_topics` bt INNER JOIN `".BIT_DB_PREFIX."liberty_comments` lcom ON(bt.`parent_id`=lcom.`content_id`) WHERE `migrate_topic_id`=?", array( $pMigrateTopicId ) ); + } + return $ret; + } + + function verify( &$pParamHash ) { + if( isset( $pParamHash['is_locked'] ) ) { + if( !is_numeric( $pParamHash['is_locked'] ) || $pParamHash['is_locked'] > 1 || $pParamHash['is_locked'] < 0 ) { + $this->mErrors[]=("Invalid topic state"); + } else { + $pParamHash['topic_store']['is_locked'] = $pParamHash['is_locked']; + } + } + if( isset( $pParamHash['is_moved'] ) ) { + if( !is_numeric( $pParamHash['is_moved'] ) || $pParamHash['is_moved'] > 1 || $pParamHash['is_moved'] < 0 ) { + $this->mErrors[]=("Invalid move state"); + } else { + $pParamHash['topic_store']['is_moved'] = $pParamHash['is_moved']; + } + } + if( !empty( $pParamHash['is_sticky'] ) ) { + if( !is_numeric( $pParamHash['is_sticky'] ) || $pParamHash['is_sticky'] > 1 || $pParamHash['is_sticky'] < 0 ) { + $this->mErrors[]=("Invalid sticky state"); + } else { + $pParamHash['topic_store']['is_sticky'] = $pParamHash['is_sticky']; + } + } + if( !empty( $pParamHash['migrate_topic_id'] ) ) { + $pParamHash['topic_store']['migrate_topic_id'] = $pParamHash['migrate_topic_id']; + } + + return( count( $this->mErrors ) == 0 && !empty( $pParamHash['topic_store'] ) ); + } + + /** + * This function stickies a topic + */ + function store( &$pParamHash ) { + global $gBitSystem; + $ret = FALSE; + if( $this->mCommentContentId && $this->verify( $pParamHash ) ) { + //$pParamHash = (($pParamHash + 1)%2); + $query_sel = "SELECT * FROM `".BIT_DB_PREFIX."boards_topics` WHERE `parent_id` = ?"; + $isStored = $this->mDb->getOne( $query_sel, array( $this->mCommentContentId ) ); + if( $isStored ) { + $result = $this->mDb->associateUpdate( 'boards_topics', $pParamHash['topic_store'], array( 'parent_id' => $this->mCommentContentId ) ); + } else { + $pParamHash['topic_store']['parent_id'] = $this->mCommentContentId; + $result = $this->mDb->associateInsert( 'boards_topics', $pParamHash['topic_store'] ); + } + $ret = TRUE; + } + return $ret; + } + + /** + * This function locks a topic + */ + function lock($state) { + global $gBitSystem; + $ret = FALSE; + if ($state==null || !is_numeric($state) || $state > 1 || $state<0) { + $this->mErrors[]=("Invalid current state"); + } else { + $state = (($state+1)%2); + $query_sel = "SELECT * FROM `".BIT_DB_PREFIX."boards_topics` WHERE `parent_id` = ?"; + $result = $this->mDb->query( $query_sel, array( $this->mCommentContentId ) ); + if($result->RowCount()==0) { + $query_ins = "INSERT INTO `".BIT_DB_PREFIX."boards_topics` (`parent_id`,`is_locked`) VALUES ( ?, ?)"; + $result = $this->mDb->query( $query_ins, array( $this->mCommentContentId, $state ) ); + } else { + $query_up = "UPDATE `".BIT_DB_PREFIX."boards_topics` SET `is_locked` = ? WHERE `parent_id` = ?"; + $result = $this->mDb->query( $query_up, array( $state, $this->mCommentContentId ) ); + } + $ret = true; + } + return $ret; + } + + /** + * This function stickies a topic + */ + function sticky($state) { + global $gBitSystem; + $ret = FALSE; + if ($state==null || !is_numeric($state) || $state > 1 || $state<0) { + $this->mErrors[]=("Invalid current state"); + } else { + $state = (($state+1)%2); + $query_sel = "SELECT * FROM `".BIT_DB_PREFIX."boards_topics` WHERE `parent_id` = ?"; + $result = $this->mDb->query( $query_sel, array( $this->mCommentContentId ) ); + if($result->RowCount()==0) { + $query_ins = "INSERT INTO `".BIT_DB_PREFIX."boards_topics` (`parent_id`,`is_sticky`) VALUES ( ?, ? )"; + $result = $this->mDb->query( $query_ins, array( $this->mCommentContentId, $state ) ); + } else { + $query_up = "UPDATE `".BIT_DB_PREFIX."boards_topics` SET `is_sticky` = ? WHERE `parent_id` = ?"; + $result = $this->mDb->query( $query_up, array( $state, $this->mCommentContentId) ); + } + $ret = TRUE; + } + return $ret; + } + + /** + * This function moves a topic to a new messageboard + */ + function moveTo($board_id) { + + // start transaction + $this->StartTrans(); + + // create a new comment letting people know it has beem moved + $lcom = new LibertyComment(); + $lcom_hash['edit']="The comments from: {$this->mInfo['title']} ({$this->mRootId}) have been is_moved to $board_id"; + $lcom_hash['title']=$this->mInfo['title']; + $lcom_hash['parent_id']=$this->mInfo['th_root_id']; + $lcom_hash['root_id']=$this->mInfo['th_root_id']; + $lcom_hash['created']=$this->mInfo['flc_created']; + $lcom_hash['last_modified']=$this->mInfo['flc_last_modified']; + $lcom->storeComment($lcom_hash); + + // map the move to the topic table + $data = array(); + $data['parent_id']=$lcom->mContentId; + $data['is_moved']=$this->mRootId; + $this->mDb->associateInsert( BIT_DB_PREFIX."boards_topics", $data ); + + // move the comment we want to move to the target board + $query = "UPDATE `".BIT_DB_PREFIX."liberty_comments` SET `root_id` = ?, `parent_id` = ? + WHERE `thread_forward_sequence` LIKE '".sprintf("%09d.", $this->mRootId)."%' AND `root_id`=`parent_id`"; + $result = $this->mDb->query( $query, array( $board_id, $board_id ) ); + + $query = "UPDATE `".BIT_DB_PREFIX."liberty_comments` SET `root_id` = ? + WHERE `thread_forward_sequence` LIKE '".sprintf("%09d.", $this->mRootId)."%'"; + $result = $this->mDb->query( $query, array( $board_id ) ); + + // end transaction + $this->CompleteTrans(); + + return TRUE; + } + + /** + * This function generates a list of records from the liberty_content database for use in a list page + */ + function getList( &$pParamHash ) { + global $gBitSystem, $gBitUser; + $BIT_DB_PREFIX = BIT_DB_PREFIX; + // this makes sure parameters used later on are set + LibertyMime::prepGetList( $pParamHash ); + + $selectSql = $joinSql = $whereSql = ''; + $bindVars = array(); + $pParamHash['include_comments'] = 'y'; + $this->getServicesSql( 'content_list_sql_function', $selectSql, $joinSql, $whereSql, $bindVars, NULL, $pParamHash ); + + // this will set $find, $sort_mode, $max_records and $offset + extract( $pParamHash ); + + if(empty($find)) { + } elseif( is_array( $find ) ) { + // you can use an array of pages + $whereSql .= " AND flc.`title` IN( ".implode( ',',array_fill( 0,count( $find ),'?' ) )." )"; + $bindVars = array_merge ( $bindVars, $find ); + } elseif( is_string( $find ) ) { + // or a string + $bindVars[] = '%'. strtoupper( $find ).'%'; + $whereSql .= " AND UPPER( lc.`title` ) LIKE ?"; + } + + // if we have the board's board_id (b) we use that, or if we have its content_id we can use that + if( (!empty( $pParamHash['b'] ) && $this->verifyId( $pParamHash['b'] )) + || (!empty( $pParamHash['content_id'] ) && $this->verifyId( $pParamHash['content_id'] )) ) { + $joinSql .= " INNER JOIN `${BIT_DB_PREFIX}boards_map` map ON (map.`topic_content_id` = lcom.`root_id`)"; + $joinSql .= " INNER JOIN `${BIT_DB_PREFIX}boards` b ON (b.`content_id` = map.`board_content_id`)"; + if(!empty($pParamHash['b'])) { + $whereSql .= " AND b.`board_id` = ?"; + $bindVars[] = (int)$pParamHash['b']; + }else{ + $whereSql .= " AND b.`content_id` = ?"; + $bindVars[] = (int)$pParamHash['content_id']; + } + } + + BitBoardTopic::loadTrack($selectSql,$joinSql); + + // use adodb's substr property + $substr = $this->mDb->substr(); + + if ( $this->mDb->mType == 'firebird' ) { + $substrSql = "SUBSTRING(s_lcom.`thread_forward_sequence` FROM 1 FOR 10) LIKE SUBSTRING(lcom.`thread_forward_sequence` FROM 1 FOR 10)"; + } else { + $substrSql = "$substr(s_lcom.`thread_forward_sequence`, 1, 10) LIKE $substr(lcom.`thread_forward_sequence`, 1, 10)"; + } + + if ($gBitSystem->isFeatureActive('boards_posts_anon_moderation') && !($gBitUser->hasPermission('p_boards_update') || $gBitUser->hasPermission('p_boards_post_update'))) { + $whereSql .= " AND ((post.`is_approved` = 1) OR (lc.`user_id` >= 0))"; + } + if ($gBitSystem->isFeatureActive('boards_posts_anon_moderation') && ($gBitUser->hasPermission('p_boards_update') || $gBitUser->hasPermission('p_boards_post_update'))) { + $selectSql .= ", ( SELECT COUNT(*) + FROM `${BIT_DB_PREFIX}liberty_comments` AS s_lcom + INNER JOIN `".BIT_DB_PREFIX."liberty_content` s_lc ON (s_lcom.`content_id` = s_lc.`content_id`) + LEFT JOIN `${BIT_DB_PREFIX}boards_posts` s ON( s_lcom.`comment_id` = s.`comment_id` ) + WHERE (".$substrSql.") AND ((s_lc.`user_id` < 0) AND (s.`is_approved` = 0 OR s.`is_approved` IS NULL))) AS unreg"; + } else { + $selectSql .= ", 0 AS unreg"; + } + + $sort_sql = "flc.".$this->mDb->convertSortmode( $sort_mode ); + + $query = "SELECT + lc.`user_id` AS flc_user_id, + lc.`created` AS flc_created, + lc.`last_modified` AS flc_last_modified, + lc.`title` AS title, + lc.`content_id` AS flc_content_id, + + COALESCE(post.`is_approved`,0) AS first_approved, + lcom.`anon_name`, + + th.`parent_id` AS th_first_id, + COALESCE(th.`is_locked`,0) AS th_is_locked, + COALESCE(th.`is_moved`,0) AS th_is_moved, + COALESCE(th.`is_sticky`,0) AS th_is_sticky, + + lcom.`comment_id` AS th_thread_id, + lcom.`root_id` AS th_root_id, + + lcom.`root_id` AS content_id, + lc.`content_type_guid` AS content_type_guid, + lc.`content_status_id` AS content_status_id, + + ( + SELECT COUNT(*) + FROM `".BIT_DB_PREFIX."liberty_comments` s_lcom + INNER JOIN `".BIT_DB_PREFIX."liberty_content` s_lc ON (s_lcom.`content_id` = s_lc.`content_id`) + WHERE (".$substrSql.") + ) AS post_count, + + ( + SELECT MAX(s_lc.created) + FROM `".BIT_DB_PREFIX."liberty_comments` s_lcom + INNER JOIN `".BIT_DB_PREFIX."liberty_content` s_lc ON (s_lcom.`content_id` = s_lc.`content_id`) + WHERE (".$substrSql.") + ) AS last_post + + $selectSql + FROM `${BIT_DB_PREFIX}liberty_comments` lcom + INNER JOIN `${BIT_DB_PREFIX}liberty_content` lc ON( lc.`content_id` = lcom.`content_id` ) + LEFT JOIN `${BIT_DB_PREFIX}boards_topics` th ON (th.`parent_id`=lcom.`content_id`) + LEFT JOIN `${BIT_DB_PREFIX}boards_posts` post ON (post.`comment_id` = lcom.`comment_id`) + $joinSql + WHERE + lcom.`root_id`=lcom.`parent_id` + $whereSql + ORDER BY + 11 DESC, + 10 ASC, + last_post DESC, + lc.created DESC + "; + + $query_cant = "SELECT count(*) + FROM `${BIT_DB_PREFIX}liberty_comments` lcom + INNER JOIN `${BIT_DB_PREFIX}liberty_content` lc ON( lc.`content_id` = lcom.`content_id` ) + LEFT JOIN `${BIT_DB_PREFIX}boards_topics` th ON (th.`parent_id`=lcom.`content_id`) + LEFT JOIN `${BIT_DB_PREFIX}boards_posts` post ON (post.`comment_id` = lcom.`comment_id`) + $joinSql + WHERE + lcom.`root_id`=lcom.`parent_id` + $whereSql"; + + $result = $this->mDb->query( $query, $bindVars, $max_records, $offset ); + $ret = array(); + while( $res = $result->fetchRow() ) { + if (empty($res['anon_name'])) $res['anon_name'] = "Anonymous"; + if ($res['th_is_moved']>0) { + $res['url']=BOARDS_PKG_URL."index.php?t=".$res['th_is_moved']; + } else { + $res['url']=BOARDS_PKG_URL."index.php?t=".$res['th_thread_id']; + } + $llc_data = BitBoardTopic::getLastPost($res); + $res = array_merge($res,$llc_data); + BitBoardTopic::track($res); + $res['flip']=BitBoardTopic::getFlipFlop($res); + if (empty($res['title'])) { + $res['title']="[Thread ".$res['th_thread_id']."]"; + } + $ret[] = $res; + } + $pParamHash["cant"] = $this->mDb->getOne( $query_cant, $bindVars ); + // add all pagination info to pParamHash + LibertyMime::postGetList( $pParamHash ); + return $ret; + } + + function getLastPost($data) { + global $gBitSystem; + if ( $this->mDb->mType == 'firebird' ) { + $substrSql = "SUBSTRING(lcom.`thread_forward_sequence` FROM 1 FOR 10)"; + } else { + $substrSql = "".$this->mDb->substr()."(lcom.`thread_forward_sequence`, 1, 10)"; + } + $whereSql = ''; + if ($gBitSystem->isFeatureActive('boards_posts_anon_moderation')) { + $whereSql = " AND ((post.`is_approved` = 1) OR (lc.`user_id` >= 0))"; + } + $BIT_DB_PREFIX = BIT_DB_PREFIX; + $query="SELECT lc.`last_modified` AS llc_last_modified, lc.`user_id` AS llc_user_id, lc.`content_id` AS llc_content_id, lcom.`anon_name` AS l_anon_name + FROM `".BIT_DB_PREFIX."liberty_comments` lcom + INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lcom.`content_id` = lc.`content_id`) + LEFT JOIN `${BIT_DB_PREFIX}boards_posts` post ON (post.`comment_id` = lcom.`comment_id`) + WHERE (".$substrSql.") LIKE '".sprintf("%09d.",$data['th_thread_id'])."%' $whereSql + ORDER BY lc.`last_modified` DESC + "; + $result = $this->mDb->getRow( $query); + if (empty($result['l_anon_name'])) $result['l_anon_name'] = "Anonymous"; + return $result; + } + + /** + * Generates the URL to the bitboard page + * @return the link to display the page. + */ + public static function getDisplayUrlFromHash( &$pParamHash ) { + global $gBitSystem; + $ret = NULL; + + if( !empty( $pParamHash['topic_id'] ) && static::verifyId( $pParamHash['topic_id'] ) ) { + $topicId = $pParamHash['topic_id']; + } elseif( !empty( $pParamHash['th_thread_id'] ) && static::verifyId( $pParamHash['th_thread_id'] ) ) { + $topicId = $pParamHash['th_thread_id']; + } + + if( !empty( $topicId ) ) { + if( $gBitSystem->isFeatureActive( 'pretty_urls' ) || $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ) { + $rewrite_tag = $gBitSystem->isFeatureActive( 'pretty_urls_extended' ) ? 'view/' : ''; + $ret = BOARDS_PKG_URL.$rewrite_tag."topic/".$topicId; + } else { + $ret = BOARDS_PKG_URL."index.php?t=".$topicId; + } + } + return $ret; + } + + public static function isLocked( $pThreadId ) { + global $gBitSystem; +/* + // remove mixed static / dynamic function invocation + if (!$pThreadId) { + $pThreadId = $this->mCommentContentId; + } else { + $pThreadId=intval($pThreadId); + } +*/ + $ret = $gBitSystem->mDb->getOne("SELECT `is_locked` FROM `".BIT_DB_PREFIX."boards_topics` WHERE `parent_id` = ?", array( (int)$pThreadId ) ); + return !empty($ret); + } + + public static function isLockedMsg( $parent_id ) { + // $parentComment = new LibertyComment(NULL,$parent_id); + // $topicId = $parentComment->mInfo['thread_forward_sequence']; + if (!empty($parent_id)) { + return BitBoardTopic::isLocked($parent_id); + } + return false; + } + + public static function isNotificationOn( $pThreadId ) { + global $gBitSystem, $gBitUser; + if ($gBitSystem->isPackageActive('boards') && $gBitSystem->isFeatureActive('boards_thread_track')) { +/* + // remove mixed static / dynamic function invocation + if (!$pThreadId) { + $pThreadId = $this->mRootId; + } + if (is_numeric($pThreadId)) { + $topicId = sprintf("%09d.",$pThreadId); + } +*/ + return $gBitSystem->mDb->getOne("SELECT SUM(`notify`) FROM `".BIT_DB_PREFIX."boards_tracking` WHERE topic_id=?", array( (int)$topicId ) ); + } + return false; + } + + function getNotificationData($pThreadId) { + global $gBitSystem, $gBitUser; + if ($gBitSystem->isPackageActive('boards') && $gBitSystem->isFeatureActive('boards_thread_track')) { + if (!$pThreadId) { + $pThreadId = $this->mRootId; + } + if (is_numeric($pThreadId)) { + $topicId = sprintf("%09d.",$pThreadId); + } + $query = "SELECT uu.user_id, uu.email, uu.login, uu.real_name, trk.`track_date`, trk.`notify` AS track_notify, trk.`notify_date` AS track_notify_date + FROM `".BIT_DB_PREFIX."boards_tracking` trk + LEFT JOIN `".BIT_DB_PREFIX."users_users` uu ON( uu.`user_id` = trk.`user_id` ) + WHERE topic_id=?"; + + $result = $gBitSystem->mDb->query( $query, array( $topicId ) ); + $ret = array(); + $ret['users']=array(); + while( $res = $result->fetchRow() ) { + $res['user'] =( isset( $res['real_name'] )? $res['real_name'] : $res['login'] ); + $ret['users'][$res['login']] = $res; + } + $ret['topic'] = new BitBoardTopic(intval($topicId)); + $ret['topic']->load(); + return $ret; + } + + return array(); + } + + function sendNotification($user) { + global $gBitSystem; + //return; + $mail_subject= "Topic Reply Notification - ".$this->mInfo['title']; + $host = 'http://'.$_SERVER['HTTP_HOST']; + //TODO: use a template for this + $mail_message = "Hello ".$user['user'].", + + You are receiving this email because you are watching the topic, \"".$this->mInfo['title']."\" at ".$gBitSystem->getConfig('site_title',"[Bitweaver Site]").". + This topic has received a reply since your last visit. + You can use the following link to view the replies made, no more notifications will be sent until you visit the topic. + + ".$host.$this->getDisplayUrl()." + + If you no longer wish to watch this topic you can either click the \"Stop watching this topic link\" found at the topic of the topic above, or by clicking the following link after logging on: + + ".$host.$this->getDisplayUrl()."¬ify=1"; + + @mail($user['email'], $mail_subject , $mail_message, "From: ".$gBitSystem->getConfig( 'site_sender_email' )."\r\nContent-type: text/plain;charset=utf-8\r\n"); + + $data = array( + 'notify_date'=>time(), + ); + + $key = array( + 'user_id' =>$user['user_id'], + 'topic_id' =>sprintf("%09d.",$this->mRootId), + ); + + $this->mDb->associateUpdate(BIT_DB_PREFIX."boards_tracking",$data,$key); + } + + function getFlipFlop($arr=false) { + if(! $arr) { + $arr = $this->mInfo; + } + global $gBitSmarty, $gBitSystem, $gBitUser; + + $flip['is_locked']['state']=$arr['th_is_locked']; + $flip['is_locked']['req']=2; + $flip['is_locked']['id']=$arr['th_thread_id']; + $flip['is_locked']['idname']='t'; + $flip['is_locked']['up']='icon-lock'; + $flip['is_locked']['upname']=tra('Thread Locked'); + $flip['is_locked']['down']='icon-unlock'; + $flip['is_locked']['downname']=tra('Thread Unlocked'); + $flip['is_locked']['perm']='p_boards_update'; + + $flip['is_sticky']['state']=$arr['th_is_sticky']; + $flip['is_sticky']['req'] = 3; + $flip['is_sticky']['id']=$arr['th_thread_id']; + $flip['is_sticky']['idname']='t'; + $flip['is_sticky']['up']='icon-exclamation-sign'; + $flip['is_sticky']['upname']=tra('Sticky Thread'); + $flip['is_sticky']['down']='icon-list'; + $flip['is_sticky']['downname']=tra('Non Sticky Thread'); + $flip['is_sticky']['perm']='p_boards_update'; + + if ($gBitSystem->isFeatureActive('boards_thread_notification') && $gBitUser->isRegistered()) { + $flip['notify']['state']=($arr['notify']['on'])*1; + $flip['notify']['req']=5; + $flip['notify']['id']=$arr['th_thread_id']; + $flip['notify']['idname']='t'; + $flip['notify']['up']='icon-bell-alt'; + $flip['notify']['upname']=tra('Reply Notification'); + $flip['notify']['down']='icon-bell'; + $flip['notify']['downname']=tra('Reply Notification Disabled'); + $flip['notify']['perm']='p_boards_read'; + } + if ($gBitSystem->isFeatureActive('boards_thread_track') && $gBitUser->isRegistered()) { + $flip['new']['state']=($arr['track']['on']&&$arr['track']['mod'])*1; + $flip['new']['req']=4; + $flip['new']['id']=$arr['th_thread_id']; + $flip['new']['idname']='t'; + $flip['new']['up']='icon-asterisk'; + $flip['new']['upname']=tra('New Posts'); +// $flip['new']['down']='icon-comment-alt'; +// $flip['new']['downname']=tra('No new posts'); + $flip['new']['perm']='p_boards_read'; + } + + return $flip; + } + + function readTopic() { + global $gBitUser, $gBitSystem; + if ($gBitSystem->isFeatureActive('boards_thread_track') && $gBitUser->isRegistered()) { + $topicId = sprintf("%09d.",$this->mRootId); + $BIT_DB_PREFIX = BIT_DB_PREFIX; + $c = $this->mDb->getOne("SELECT COUNT(*) FROM `".BIT_DB_PREFIX."boards_tracking` WHERE user_id=? AND topic_id='$topicId'",array($gBitUser->mUserId)); + + $data = array( + 'user_id' =>$gBitUser->mUserId, + 'topic_id' =>$topicId, + 'track_date'=>time(), + ); + + if ($c == 0) { + $this->mDb->associateInsert(BIT_DB_PREFIX."boards_tracking",$data); + } else { + $key = array( + 'user_id' =>$gBitUser->mUserId, + 'topic_id' =>$topicId, + ); + $this->mDb->associateUpdate(BIT_DB_PREFIX."boards_tracking",$data,$key); + } + $this->mInfo['track']['mod']=false; + } + } + + function readTopicSet($pState) { + global $gBitUser, $gBitSystem; + if ($gBitSystem->isFeatureActive('boards_thread_track') && $gBitUser->isRegistered()) { + $topicId = sprintf("%09d.",$this->mRootId); + $ret = FALSE; + if ($pState==null || !is_numeric($pState) || $pState > 1 || $pState<0) { + $this->mErrors[]=("Invalid current state"); + } else { + $pState = (($pState+1)%2); + if ($pState == 0) { + $this->readTopic(); + } else { + $this->mDb->query("DELETE FROM `".BIT_DB_PREFIX."boards_tracking` WHERE user_id=$gBitUser->mUserId AND topic_id='$topicId'"); + } + $ret = true; + } + return $ret; + } + } + + function notify($pState) { + global $gBitUser, $gBitSystem; + if ($gBitSystem->isFeatureActive('boards_thread_track') && $gBitUser->isRegistered()) { + $topicId = sprintf("%09d.",$this->mRootId); + $ret = FALSE; + if ($pState==null || !is_numeric($pState) || $pState > 1 || $pState<0) { + $this->mErrors[]=("Invalid current state"); + } else { + $pState = (($pState+1)%2); + $query_sel = "SELECT * FROM `".BIT_DB_PREFIX."boards_tracking` WHERE user_id=$gBitUser->mUserId AND topic_id='$topicId'"; + $data = array( + 'user_id' =>$gBitUser->mUserId, + 'topic_id' =>$topicId, + 'notify'=>$pState, + ); + $c = $this->mDb->getOne( $query_sel ); + if ($c == 0) { + $this->mDb->associateInsert(BIT_DB_PREFIX."boards_tracking",$data); + } else { + $key = array( + 'user_id' =>$gBitUser->mUserId, + 'topic_id' =>$topicId, + ); + $this->mDb->associateUpdate(BIT_DB_PREFIX."boards_tracking",$data,$key); + } + $ret = true; + } + return $ret; + } + } + + function loadTrack(&$selectSql,&$joinSql) { + global $gBitUser, $gBitSystem; + if($gBitUser->isRegistered() && ($gBitSystem->isFeatureActive('boards_thread_track') || $gBitSystem->isFeatureActive('boards_thread_notify'))) { + $selectSql .= ", trk.`track_date`, trk.`notify` AS track_notify, trk.`notify_date` AS track_notify_date "; + $joinSql .= " LEFT JOIN `".BIT_DB_PREFIX."boards_tracking` trk ON (trk.`topic_id`=lcom.`thread_forward_sequence` AND ( trk.`user_id` = ".$gBitUser->mUserId." OR trk.`user_id` IS NULL ) ) "; + } + } + + function track(&$res) { + global $gBitUser, $gBitSystem; + if($gBitUser->isRegistered() && $gBitSystem->isFeatureActive('boards_thread_track') && $res['th_is_moved']<=0) { + $res['track']['on'] = true; + $res['track']['date'] = $res['track_date']; + if (empty($res['llc_last_modified'])) { + $res['llc_last_modified']=0; + } + if ($res['llc_last_modified']>$res['track_date']) { + $res['track']['mod'] = true; + } else { + $res['track']['mod'] = false; + } + } else { + $res['track']['on'] = false; + } + unset($res['track_date']); + if($gBitUser->isRegistered() && $gBitSystem->isFeatureActive('boards_thread_notification') && $res['th_is_moved']<=0) { + $res['notify']['on'] = (!empty($res['track_notify'])); + if ($res['notify']['on']) { + $res['notify']['date']=$res['track_notify_date']; + } + } else { + $res['notify']['on'] = false; + } + unset($res['track_notify_date']); + unset($res['track_notify']); + } + + function getRootObj(){ + if ( !is_object( $this->mRootObj ) && !empty( $this->mInfo['root_id'] ) ){ + if ( $obj = LibertyBase::getLibertyObject( $this->mInfo['root_id'] ) ) { + $this->mRootObj = $obj; + } + } + return $this->mRootObj; + } +} +?> |
