* @version $Revision$
* @package boards
*/
/**
* required setup
*/
namespace Bitweaver\Boards;
use Bitweaver\BitBase;
use Bitweaver\KernelTools;
use Bitweaver\Liberty\LibertyComment;
use Bitweaver\Users\RoleUser;
use Messages;
/**
* @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
*/
public function verify( array &$pParamHash ): bool {
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
*/
public function store( array &$pParamHash ): bool {
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, [ $this->mCommentId ] );
if( $isStored ) {
$result = $this->mDb->associateUpdate( 'boards_posts', $pParamHash['post_store'], [ '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
*/
public function loadMetaData(): void {
if ($this->isValid()) {
if (!isset($this->mInfo['accepted'])) {
$key = ['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","
\n",$data['warned_message']);
}
$this->mInfo=array_merge($this->mInfo,$data);
}
}
}
}
/**
* This function removes a bitboard entry
**/
public function expunge(): bool {
if( $this->isValid() ) {
$this->StartTrans();
// parent actually has deletion of rows in boards for constraint reasons
if( parent::expunge() ) {
$this->CompleteTrans();
} else {
$this->mDb->RollbackTrans();
}
}
return true;
}
/**
* This function gets all the post relating to a topic
*/
public function getComments( $pContentId = null, $pMaxComments = null, $pOffset = null, $pSortOrder = null, $pDisplayMode = null ) {
global $gBitUser, $gBitSystem;
$joinSql = $selectSql = $whereSql = '';
$ret = [];
$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 = [];
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 = [ '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 = [];
if( $result = $this->mDb->query( $sql, $bindVars, $pMaxComments, $pOffset ) ) {
while( $row = $result->FetchRow() ) {
if (empty($row['anon_name'])) {
$row['anon_name'] = "Anonymous";
}
$row['user_avatar_url'] = ( $row['avatar_file_name'] ) ? \Bitweaver\Liberty\liberty_fetch_thumbnail_url( [
'source_file' => \Bitweaver\Liberty\liberty_mime_get_source_file( [ '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',
] ) : false;
if (!empty($row['warned_message'])) {
$row['warned_message'] = str_replace("\n","
\n",$row['warned_message']);
}
$row['data'] = trim( $row['data'] );
$row['user_url'] = RoleUser::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,[ (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']] = [];
}
$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
*/
public function getList( &$pListHash ) {
global $gBitUser, $gBitSystem;
$this->prepGetList( $pListHash );
$joinSql = $selectSql = $whereSql = '';
$ret = [];
$contentId = $this->mCommentId;
// $mid = 'ORDER BY `thread_forward_sequence` ASC';
$bindVars = [];
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'] ?? 0 ) ) {
$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 = [];
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";
$row['user_avatar_url'] = ( !empty( $row['avatar_file_name'] ) ) ? \Bitweaver\Liberty\liberty_fetch_thumbnail_url( [
'source_file' => \Bitweaver\Liberty\liberty_mime_get_source_file( [ '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',
] ) : false;
unset($row['avatar_file_name']);
if (!empty($row['warned_message'])) {
$row['warned_message'] = str_replace("\n","
\n",$row['warned_message']);
}
$row['data'] = trim($row['data']);
$row['user_url']=RoleUser::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
*/
public function getNumComments($pContentId = null) {
$ret = 0;
$contentId = $this->mCommentId;
$bindVars = [];
$joinSql = $selectSql = $whereSql = '';
$paramHash = [ '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
*/
public 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 string 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;
}
/**
* Summary of getContactUrl
* @return string
*/
public function getContactUrl(): string {
return '';
}
/**
* Summary of getTopicId
* @return int
*/
public function getTopicId() {
return boards_get_topic_comment( $this->getField( 'thread_forward_sequence') );
}
public function modApprove() {
$data['is_approved'] = 1;
$this->setMetaData($data);
}
public function modReject() {
$this->deleteComment();
}
public function modWarn($message) {
global $gBitSystem, $gBitUser;
if (empty($message)) {
$gBitSystem->fatalError("No Warning Message Given.
A post cannot be warned without a message");
}
$data['is_warned']=1;
$data['warned_message']=$message;
$this->setMetaData($data);
if ($gBitSystem->isPackageActive('messages')) {
$u = new RoleUser($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 = [
'to_login' => $userInfo['login'],
'to' => $userInfo['real_name'],
'subject' => KernelTools::tra( 'Warned Post' ) . ': ' . $this->mInfo['title'],
'priority' => 4,
];
$pm->postMessage( $msgHash );
}
}
public function setMetaData($data) {
if ($this->isValid()) {
$key = [ '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);
}
}
}
}