4014 lines
127 KiB
PHP
4014 lines
127 KiB
PHP
<?php
|
|
/**
|
|
* <pre>
|
|
* Invision Power Services
|
|
* IP.Board v3.3.4
|
|
* Comments library
|
|
* Last Updated: $Date: 2012-06-12 10:14:49 -0400 (Tue, 12 Jun 2012) $
|
|
* </pre>
|
|
*
|
|
* @author $Author: bfarber $
|
|
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
|
* @license http://www.invisionpower.com/company/standards.php#license
|
|
* @package IP.Board
|
|
* @subpackage Members
|
|
* @link http://www.invisionpower.com
|
|
* @since 20th February 2002
|
|
* @version $Revision: 10914 $
|
|
*/
|
|
|
|
if ( ! defined( 'IN_IPB' ) )
|
|
{
|
|
print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.";
|
|
exit();
|
|
}
|
|
|
|
class messengerFunctions
|
|
{
|
|
/**
|
|
* Registry Object Shortcuts
|
|
*
|
|
* @var object
|
|
*/
|
|
protected $registry;
|
|
protected $DB;
|
|
protected $settings;
|
|
protected $request;
|
|
protected $lang;
|
|
protected $member;
|
|
protected $memberData;
|
|
protected $cache;
|
|
protected $caches;
|
|
|
|
/**
|
|
* Directory Data
|
|
*
|
|
* @var array
|
|
*/
|
|
public $_dirData = array();
|
|
|
|
/**
|
|
* Folder Jump HTML
|
|
*
|
|
* @var string
|
|
*/
|
|
public $_jumpMenu;
|
|
|
|
/**
|
|
* Current folder ID
|
|
*
|
|
* @var string
|
|
*/
|
|
public $_currentFolderID;
|
|
|
|
/**
|
|
* Boolean flag
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $forceMessageToSend = FALSE;
|
|
|
|
/**
|
|
* More exception data
|
|
* Should write a custom exception handler really
|
|
*
|
|
* @var array
|
|
*/
|
|
public $exceptionData = array();
|
|
|
|
/**
|
|
* No. messages per page to view
|
|
*
|
|
* @var int
|
|
*/
|
|
public $messagesPerPage = 20;
|
|
|
|
/**
|
|
* Folder filter.
|
|
* Mostly used for 'myconvo' folder currently, but added
|
|
* here so it's done proper-like
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_folderFilter = '';
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param object $registry Registry object
|
|
* @return @e void
|
|
*/
|
|
public function __construct( ipsRegistry $registry )
|
|
{
|
|
/* Make object */
|
|
$this->registry = $registry;
|
|
$this->DB = $this->registry->DB();
|
|
$this->settings =& $this->registry->fetchSettings();
|
|
$this->request =& $this->registry->fetchRequest();
|
|
$this->lang = $this->registry->getClass('class_localization');
|
|
$this->member = $this->registry->member();
|
|
$this->memberData =& $this->registry->member()->fetchMemberData();
|
|
$this->cache = $this->registry->cache();
|
|
$this->caches =& $this->registry->cache()->fetchCaches();
|
|
|
|
//-----------------------------------------
|
|
// Need to reset?
|
|
//-----------------------------------------
|
|
|
|
if ( $this->memberData['msg_count_reset'] )
|
|
{
|
|
$this->memberData['pconversation_filters'] = $this->resetMembersFolderCounts( $this->memberData['member_id'] );
|
|
$this->resetMembersTotalTopicCount( $this->memberData['member_id'] );
|
|
$this->resetMembersNewTopicCount( $this->memberData['member_id'] );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// INIT Folder contents
|
|
//-----------------------------------------
|
|
|
|
$folderContents = array();
|
|
|
|
//-----------------------------------------
|
|
// Do a little set up, do a litle dance, get
|
|
// down tonight! *boogie*
|
|
//-----------------------------------------
|
|
|
|
$this->_dirData = $this->explodeFolderData( $this->memberData['pconversation_filters'] );
|
|
|
|
//-----------------------------------------
|
|
// Do we have VID?
|
|
// No, it's just the way we walk! Haha, etc.
|
|
//-----------------------------------------
|
|
|
|
if ( $this->request['folderID'] AND $this->request['folderID'] )
|
|
{
|
|
$this->_currentFolderID = $this->request['folderID'];
|
|
}
|
|
else
|
|
{
|
|
/* Got any new messages? If so, show that. If not, show myconvo
|
|
I'm sure you could have figured that out without this silly comment...*/
|
|
$this->_currentFolderID = ( $this->_dirData['new']['count'] ) ? 'new' : 'myconvo';
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Print folder links
|
|
//-----------------------------------------
|
|
|
|
foreach( $this->_dirData as $id => $data )
|
|
{
|
|
if ( $data['protected'] AND $id != 'myconvo' )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
$folderContents[] = "<option value='move_$id'>{$data['real']}</option>";
|
|
}
|
|
|
|
if ( count( $folderContents ) > 1 )
|
|
{
|
|
$this->_jumpMenu = implode( "\n", $folderContents );
|
|
}
|
|
else
|
|
{
|
|
$this->_jumpMenu = '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flood control check
|
|
*
|
|
* @return bool (return TRUE for OK to continue, FALSE for flood stopped) Also populates $this->exceptionData[0] with time that next PM can be made
|
|
*/
|
|
public function floodControlCheck()
|
|
{
|
|
/* Disabled PM flood? */
|
|
if ( ! $this->memberData['g_pm_flood_mins'] )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Forcing a PM, bypass the check */
|
|
if ( $this->forceMessageToSend === TRUE )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Ensure we have a member */
|
|
if ( ! $this->memberData['member_id'] )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* Still here? Grab their last sent PM */
|
|
$pm = $this->DB->buildAndFetch( array( 'select' => 'MAX(mt_date) as max',
|
|
'from' => 'message_topics',
|
|
'where' => 'mt_starter_id=' . $this->memberData['member_id'] ) );
|
|
|
|
|
|
if ( $pm['max'] )
|
|
{
|
|
$_check = time() - ( intval( $this->memberData['g_pm_flood_mins'] ) * 60 );
|
|
|
|
if ( $pm['max'] >= $_check )
|
|
{
|
|
/* Last PM is more recent */
|
|
$this->exceptionData = array( 0 => $this->registry->class_localization->getDate( $pm['max'] + ( intval( $this->memberData['g_pm_flood_mins'] ) * 60 ), 'LONG', 1 ) );
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Last PM is older */
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Check number of messages sent today vs your max per day setting
|
|
*
|
|
* @return bool Can send more
|
|
*/
|
|
public function checkHasHitMax()
|
|
{
|
|
if( $this->memberData['g_pm_perday'] )
|
|
{
|
|
$_time = time() - ( 60 * 60 * 24 );
|
|
$_total = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as total', 'from' => 'message_topics', 'where' => 'mt_start_time > ' . $_time . ' AND mt_starter_id=' . $this->memberData['member_id'] ) );
|
|
|
|
if( $_total['total'] >= $this->memberData['g_pm_perday'] )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Set a folder filter
|
|
* Mostly used for myconvo but added here for extensibility in the future
|
|
*
|
|
* @param string
|
|
* @return @e void
|
|
*/
|
|
public function addFolderFilter( $filter )
|
|
{
|
|
$this->_folderFilter = $filter;
|
|
}
|
|
|
|
/**
|
|
* Fetch new PM notification
|
|
*
|
|
* @param int Member ID
|
|
* @return array Array of data
|
|
*/
|
|
public function fetchUnreadNotifications( $memberID )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$return = array();
|
|
$memberID = intval( $memberID );
|
|
$members = array();
|
|
$_members = array();
|
|
|
|
//-----------------------------------------
|
|
// Fetch messages
|
|
//-----------------------------------------
|
|
|
|
$this->DB->build( array( 'select' => 'map.*',
|
|
'from' => array( 'message_topic_user_map' => 'map' ),
|
|
'where' => 'map.map_user_active=1 AND map.map_user_banned=0 AND map.map_has_unread=1 AND map.map_user_id=' . $memberID,
|
|
'add_join' => array( array( 'select' => 't.*',
|
|
'from' => array( 'message_topics' => 't' ),
|
|
'where' => 't.mt_id=map_topic_id',
|
|
'type' => 'inner' ),
|
|
array( 'select' => 'p.*',
|
|
'from' => array( 'message_posts' => 'p' ),
|
|
'where' => 'p.msg_id=t.mt_last_msg_id',
|
|
'type' => 'inner' ) ) ) );
|
|
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
$return[ $row['msg_date'] . '.' . $row['msg_id'] ] = $row;
|
|
|
|
/* Members to load */
|
|
$_members[ $row['mt_starter_id'] ] = $row['mt_starter_id'];
|
|
$_members[ $row['msg_author_id'] ] = $row['msg_author_id'];
|
|
}
|
|
|
|
/* Got anything? */
|
|
if ( ! count( $return ) )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/* Load 'em */
|
|
if ( count( $_members ) )
|
|
{
|
|
$members = IPSMember::load( $_members, 'all' );
|
|
}
|
|
|
|
/* Parse 'em */
|
|
if ( count( $members ) )
|
|
{
|
|
foreach( $members as $id => $data )
|
|
{
|
|
$members[ $id ] = IPSMember::buildDisplayData( $data );
|
|
}
|
|
}
|
|
|
|
/* Add 'em */
|
|
foreach( $return as $sortID => $data )
|
|
{
|
|
/* membahs */
|
|
$data['starterData'] = $members[ $data['mt_starter_id'] ];
|
|
$data['authorData'] = $members[ $data['msg_author_id'] ];
|
|
|
|
/* Format message */
|
|
$data['msg_post'] = IPSText::getTextClass('bbcode')->stripAllTags( $data['msg_post'] ); //$this->_formatMessageForDisplay( $data['msg_post'] );
|
|
|
|
/* Type of PM */
|
|
if ( $data['msg_id'] == $data['mt_first_msg_id'] )
|
|
{
|
|
$data['_type'] = 'new';
|
|
}
|
|
else
|
|
{
|
|
$data['_type'] = 'reply';
|
|
}
|
|
|
|
$return[ $sortID ] = $data;
|
|
}
|
|
|
|
/* Reverse sort it (latest first) */
|
|
krsort( $return );
|
|
|
|
/* Return 'em */
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Search messages
|
|
* Searches messages. It really does.
|
|
*
|
|
* @param int Member ID who be searching!
|
|
* @param string Words to search (probably tainted at this point, so be careful!)
|
|
* @param int Offset start
|
|
* @param int Number of results to return
|
|
* @param array Array of folders to search (send nothing to search all)
|
|
* @return array array( 'totalMatches' => int, 'results' => Array of topics that match the search words )
|
|
*/
|
|
public function searchMessages( $memberID, $words, $start=0, $end=50, $folders=array() )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$results = array( 'totalMatches' => 0, 'results' => array() );
|
|
$_memberIDs = array();
|
|
$_members = array();
|
|
$_results = array();
|
|
|
|
//-----------------------------------------
|
|
// Load up library
|
|
//-----------------------------------------
|
|
|
|
$file = IPSLib::getAppDir( 'members' ) . '/sql/messengerSearch_' . strtolower( $this->settings['sql_driver'] ) . '.php';
|
|
|
|
if ( ! is_file( $file ) )
|
|
{
|
|
return $results;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Fetch 'em
|
|
//-----------------------------------------
|
|
|
|
$classToLoad = IPSLib::loadLibrary( $file, 'messengerSearch', 'members' );
|
|
$search = new $classToLoad( $this->registry );
|
|
|
|
$search->execute( $memberID, $words, $start, $end, $folders );
|
|
|
|
$results['totalMatches'] = $search->fetchTotalRows();
|
|
$_results = $search->fetchResults();
|
|
|
|
//-----------------------------------------
|
|
// Add in member data...
|
|
//-----------------------------------------
|
|
|
|
if ( ! count( $_results ) )
|
|
{
|
|
return $results;
|
|
}
|
|
|
|
foreach( $_results as $mtID => $mtData )
|
|
{
|
|
$_memberIDs[ $mtData['mt_starter_id'] ] = $mtData['mt_starter_id'];
|
|
$_memberIDs[ $mtData['mt_to_member_id'] ] = $mtData['mt_to_member_id'];
|
|
}
|
|
|
|
/* Load members */
|
|
if ( count( $_memberIDs ) )
|
|
{
|
|
$_members = IPSMember::load( array_keys( $_memberIDs ), 'all' );
|
|
}
|
|
|
|
/* Let's sort out the ignore & photos at once for everyone */
|
|
if( count($_members) )
|
|
{
|
|
foreach( $_members as $_mid => $_mdata )
|
|
{
|
|
$_mdata['_canBeBlocked'] = IPSMember::isIgnorable( $_mdata['member_group_id'], $_mdata['mgroup_others'], 'pm' );
|
|
|
|
$_members[ $_mid ] = IPSMember::buildProfilePhoto( $_mdata );
|
|
}
|
|
}
|
|
|
|
/* Final result parse */
|
|
foreach( $_results as $mtID => $mtData )
|
|
{
|
|
$mtData['_starterMemberData'] = $_members[ $mtData['mt_starter_id'] ];
|
|
$mtData['_toMemberData'] = $_members[ $mtData['mt_to_member_id'] ];
|
|
$mtData['_lastMsgAuthor'] = $_members[ $mtData['msg_author_id'] ];
|
|
|
|
$mtData['_folderName'] = $this->_dirData[ $mtData['map_folder_id'] ]['real'];
|
|
|
|
$results['results'][ $mtID ] = $mtData;
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Block / unblock a member
|
|
*
|
|
* @param int Member ID to block
|
|
* @param int Member ID who is attempting to block
|
|
* @param int Topic ID to apply block to
|
|
* @param boolean TRUE is block, FALSE is unblock
|
|
* @return @e void
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* NO_PERMISSION User does not have permission to access this topic
|
|
* NO_BLOCK_PERMISSION User does not have the ability to block anyone
|
|
* CANNOT_BLOCK_STARTER Cannot (un)block the topic starter, that's just plain mean!
|
|
* CANNOT_BLOCK_USER Cannot (un)block the member because they either are not involved with that topic or they cannot be blocked
|
|
* </code>
|
|
*/
|
|
public function toggleTopicBlock( $blockID, $blockerID, $topicID, $block )
|
|
{
|
|
$topicData = $this->fetchTopicData( $topicID );
|
|
$_members = IPSMember::load( array( $blockID, $blockerID ), 'extendedProfile,groups' );
|
|
$blockMemberData = $_members[ $blockID ];
|
|
$blockerMemberData = $_members[ $blockerID ];
|
|
$currentParticipants = $this->fetchTopicParticipants( $topicID );
|
|
|
|
/* Can access this topic? */
|
|
if ( $this->canAccessTopic( $blockerMemberData['member_id'], $topicData, $currentParticipants, TRUE ) !== TRUE )
|
|
{
|
|
throw new Exception( 'NO_PERMISSION' );
|
|
}
|
|
|
|
/* Topic starter? */
|
|
if ( $topicData['mt_starter_id'] == $blockID )
|
|
{
|
|
throw new Exception( 'CANNOT_BLOCK_STARTER' );
|
|
}
|
|
|
|
/* Does the person we are attempting to block exist? */
|
|
if ( ! isset($currentParticipants[ $blockID ]) )
|
|
{
|
|
throw new Exception( 'CANNOT_BLOCK_USER' );
|
|
}
|
|
|
|
/* Can they be blocked? */
|
|
if ( IPSMember::isIgnorable( $blockMemberData['member_group_id'], $blockMemberData['mgroup_others'], 'pm' ) !== TRUE )
|
|
{
|
|
throw new Exception( 'CANNOT_BLOCK_USER' );
|
|
}
|
|
|
|
/* Can we actually block anyone? */
|
|
if ( ( $topicData['mt_starter_id'] != $blockerID ) AND ( ! $blockerMemberData['g_is_supmod'] ) )
|
|
{
|
|
throw new Exception( 'NO_BLOCK_PERMISSION' );
|
|
}
|
|
|
|
/* Ok... */
|
|
if ( $block === TRUE )
|
|
{
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_user_active' => 0, 'map_user_banned' => 1 ), 'map_user_id=' . $blockID . ' AND map_topic_id=' . $topicID . ' AND map_user_active=1' );
|
|
}
|
|
else
|
|
{
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_user_active' => 1, 'map_user_banned' => 0 ), 'map_user_id=' . $blockID . ' AND map_topic_id=' . $topicID . ' AND map_user_banned=1' );
|
|
$this->DB->update( 'message_topics', array( 'mt_to_count' => count( $currentParticipants ) - 1 ), 'mt_id=' . $topicID );
|
|
}
|
|
|
|
$this->resetMembersNewTopicCount( $blockID );
|
|
$this->resetMembersTotalTopicCount( $blockID );
|
|
$this->resetMembersFolderCounts( $blockID );
|
|
}
|
|
|
|
/**
|
|
* Toggles notifications
|
|
*
|
|
* @param int Owner Member ID
|
|
* @param array Array of IDs to toggle read / unread
|
|
* @param boolean TRUE notify on / FALSE notify off
|
|
* @return bool
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* NO_SUCH_MEMBER: The member ID does not exist
|
|
* NO_IDS_SELECTED No IDs to move (empty id array)
|
|
* </code>
|
|
*/
|
|
public function toggleNotificationStatus( $memberID, $ids, $notifyStatus='toggle' )
|
|
{
|
|
//-----------------------------------------
|
|
// Grab data
|
|
//-----------------------------------------
|
|
|
|
$memberData = IPSMember::load( $memberID, 'groups,extendedProfile' );
|
|
|
|
if ( ! $memberData['member_id'] )
|
|
{
|
|
throw new Exception( "NO_SUCH_MEMBER");
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Check...
|
|
//-----------------------------------------
|
|
|
|
if ( ! is_array( $ids ) OR ! count( $ids ) )
|
|
{
|
|
throw new Exception("NO_IDS_SELECTED");
|
|
}
|
|
|
|
$idString = implode( ",", $ids );
|
|
|
|
//-----------------------------------------
|
|
// Toggle...
|
|
//-----------------------------------------
|
|
|
|
if ( $notifyStatus === TRUE )
|
|
{
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_ignore_notification' => 0 ), "map_user_id=".$memberData['member_id']." AND map_topic_id IN ($idString)" );
|
|
}
|
|
else if ( $notifyStatus == 'toggle' )
|
|
{
|
|
$_on = array();
|
|
$_off = array();
|
|
|
|
$this->DB->build( array( 'select' => '*',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => "map_user_id=".$memberData['member_id']." AND map_topic_id IN ($idString)" ) );
|
|
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
if ( $row['map_ignore_notification'] )
|
|
{
|
|
$_on[] = $row['map_topic_id'];
|
|
}
|
|
else
|
|
{
|
|
$_off[] = $row['map_topic_id'];
|
|
}
|
|
}
|
|
|
|
if ( count( $_on ) )
|
|
{
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_ignore_notification' => 0 ), "map_user_id=".$memberData['member_id']." AND map_topic_id IN (" . implode(",",$_on). ")" );
|
|
}
|
|
|
|
if ( count( $_off ) )
|
|
{
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_ignore_notification' => 1 ), "map_user_id=".$memberData['member_id']." AND map_topic_id IN (" . implode(",",$_off). ")" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_ignore_notification' => 1 ), "map_user_id=".$memberData['member_id']." AND map_topic_id IN ($idString)" );
|
|
|
|
}
|
|
|
|
/* Recount */
|
|
$this->resetMembersFolderCounts( $memberData['member_id'] );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Toggles read/unread status
|
|
*
|
|
* @param int Owner Member ID
|
|
* @param array Array of IDs to toggle read / unread
|
|
* @param boolean TRUE mark as read / FALSE mark as unread
|
|
* @return bool
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* NO_SUCH_MEMBER: The member ID does not exist
|
|
* NO_IDS_SELECTED No IDs to move (empty id array)
|
|
* </code>
|
|
*/
|
|
public function toggleReadStatus( $memberID, $ids, $markAsRead )
|
|
{
|
|
//-----------------------------------------
|
|
// Grab data
|
|
//-----------------------------------------
|
|
|
|
$memberData = IPSMember::load( $memberID, 'groups,extendedProfile' );
|
|
|
|
if ( ! $memberData['member_id'] )
|
|
{
|
|
throw new Exception( "NO_SUCH_MEMBER");
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Check...
|
|
//-----------------------------------------
|
|
|
|
if ( ! is_array( $ids ) OR ! count( $ids ) )
|
|
{
|
|
throw new Exception("NO_IDS_SELECTED");
|
|
}
|
|
|
|
$idString = implode( ",", $ids );
|
|
|
|
//-----------------------------------------
|
|
// Mark as read...
|
|
//-----------------------------------------
|
|
|
|
if ( $markAsRead === TRUE )
|
|
{
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_has_unread' => 0 ), "map_user_id=".$memberData['member_id']." AND map_topic_id IN ($idString)" );
|
|
}
|
|
else
|
|
{
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_has_unread' => 1 ), "map_user_id=".$memberData['member_id']." AND map_topic_id IN ($idString)" );
|
|
}
|
|
|
|
/* Recount */
|
|
$this->resetMembersFolderCounts( $memberData['member_id'] );
|
|
$this->resetMembersNewTopicCount( $memberData['member_id'] );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Add participants to a topic
|
|
*
|
|
* @param int Topic ID
|
|
* @param array Array of IDs to invite
|
|
* @param int Member adding them (ie you)
|
|
* @return mixed bool or exception
|
|
*
|
|
* <code>
|
|
* EXCEPTION CODES:
|
|
* NO_PERMISSION User does not have permission to access this topic
|
|
* NOT_ALL_INVITE_USERS_EXIST Not all the users you've invited exist
|
|
* INVITE_USERS_BLOCKED Some of the users you've invited are blocked
|
|
* NO_ONE_TO_INVITE No one left to invite
|
|
* CANT_INVITE_SELF: The sender is in the invite list
|
|
* CANT_INVITE_RECIPIENT: The main recipient is in the invite list
|
|
* CANT_INVITE_RECIPIENT_EXIST: One or more recipients are already participating in this conversation
|
|
* </code>
|
|
*/
|
|
public function addTopicParticipants( $topicID, $invitedUsers, $readingMemberID )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$topicData = $this->fetchTopicData( $topicID );
|
|
$memberData = IPSMember::load( intval( $readingMemberID ), 'extendedProfile,groups' );
|
|
$currentParticipants = $this->fetchTopicParticipants( $topicID );
|
|
|
|
//-----------------------------------------
|
|
// Can access this topic?
|
|
//-----------------------------------------
|
|
|
|
if ( $this->canAccessTopic( $memberData['member_id'], $topicData, $currentParticipants ) !== TRUE )
|
|
{
|
|
throw new Exception( 'NO_PERMISSION' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Build invited users
|
|
//-----------------------------------------
|
|
|
|
$invitedUsersData = $this->checkAndReturnInvitedUsers( $invitedUsers, $memberData, count($currentParticipants) );
|
|
|
|
if ( isset($invitedUsersData[ $topicData['mt_starter_id'] ]) )
|
|
{
|
|
if ( $memberData['member_id'] == $topicData['mt_starter_id'] )
|
|
{
|
|
throw new Exception( 'CANT_INVITE_SELF' );
|
|
}
|
|
}
|
|
|
|
if ( isset($invitedUsersData[ $topicData['mt_to_member_id'] ]) OR isset($invitedUsersData[ $topicData['mt_starter_id'] ]) )
|
|
{
|
|
throw new Exception( 'CANT_INVITE_RECIPIENT_EXIST' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Knock out ones that are already participated
|
|
// At this point $currentParticipants contains non-active
|
|
// participants. This is OK as we don't want the ability
|
|
// to keep re-inviting those who choose to leave.
|
|
//-----------------------------------------
|
|
|
|
$existInBoth = array_intersect( array_keys( $currentParticipants ), array_keys( $invitedUsersData ) );
|
|
|
|
if ( count( $existInBoth ) )
|
|
{
|
|
foreach( $existInBoth as $id )
|
|
{
|
|
unset( $invitedUsersData[ $id ] );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Anything left?
|
|
//-----------------------------------------
|
|
|
|
if ( ! count( $invitedUsersData ) )
|
|
{
|
|
throw new Exception( 'NO_ONE_TO_INVITE' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Update the topic
|
|
// Now we can strip non-active participants
|
|
//-----------------------------------------
|
|
|
|
$__topicParticipants = array_merge( array_keys( $this->_stripNonActiveParticipants( $currentParticipants ) ), array_keys( $invitedUsersData ) );
|
|
|
|
/* Fix up so they're unique and indexed by member ID */
|
|
if ( is_array( $__topicParticipants ) AND count ( $__topicParticipants ) )
|
|
{
|
|
foreach( $__topicParticipants as $_mid )
|
|
{
|
|
$_topicParticipants[ $_mid ] = $_mid;
|
|
}
|
|
}
|
|
|
|
/* Remove topic starter */
|
|
unset( $_topicParticipants[ $topicData['mt_starter_id'] ] );
|
|
|
|
/* Remove recipient */
|
|
unset( $_topicParticipants[ $topicData['mt_to_member_id'] ] );
|
|
|
|
$this->DB->update( 'message_topics', array( 'mt_invited_members' => serialize( $_topicParticipants ),
|
|
'mt_to_count' => count( $_topicParticipants ) + 1 ), 'mt_id=' . $topicID );
|
|
|
|
//-----------------------------------------
|
|
// Add the users to the invite tree
|
|
//-----------------------------------------
|
|
|
|
foreach( $invitedUsersData as $id => $toMember )
|
|
{
|
|
$this->DB->insert( 'message_topic_user_map', array( 'map_user_id' => $id,
|
|
'map_topic_id' => $topicID,
|
|
'map_folder_id' => 'myconvo',
|
|
'map_user_active' => 1,
|
|
'map_has_unread' => 1,
|
|
'map_user_banned' => 0,
|
|
'map_read_time' => 0,
|
|
'map_left_time' => 0,
|
|
'map_ignore_notification' => 0,
|
|
'map_last_topic_reply' => $topicData['mt_last_post_time'] ) );
|
|
|
|
|
|
$new_vdir = $this->rebuildFolderCount( $toMember['member_id'], array( 'myconvo' => 'plus:1', 'new' => 'plus:1' ), TRUE, array( 'core' => array( 'msg_count_total' => 'plus:1',
|
|
'msg_count_new' => 'plus:1' ) ) );
|
|
|
|
//-----------------------------------------
|
|
// Notifications library
|
|
//-----------------------------------------
|
|
|
|
$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . '/sources/classes/member/notifications.php', 'notifications' );
|
|
$notifyLibrary = new $classToLoad( $this->registry );
|
|
|
|
$toMember['language'] = $toMember['language'] == "" ? IPSLib::getDefaultLanguage() : $toMember['language'];
|
|
|
|
IPSText::getTextClass('email')->getTemplate( "personal_convo_invite", $toMember['language'] );
|
|
|
|
IPSText::getTextClass('email')->buildMessage( array(
|
|
'NAME' => $toMember['members_display_name'],
|
|
'POSTER' => $memberData['members_display_name'],
|
|
'TITLE' => $topicData['mt_title'],
|
|
'LINK' => "?app=members&module=messaging§ion=view&do=showConversation&topicID={$topicID}" ) );
|
|
|
|
IPSText::getTextClass('email')->subject = sprintf(
|
|
IPSText::getTextClass('email')->subject,
|
|
$this->registry->output->buildSEOUrl( 'showuser=' . $memberData['member_id'], 'public', $memberData['members_seo_name'], 'showuser' ),
|
|
$memberData['members_display_name'],
|
|
$this->registry->output->buildUrl( "app=members&module=messaging§ion=view&do=showConversation&topicID={$topicID}", 'public' )
|
|
);
|
|
|
|
$notifyLibrary->setMember( $toMember );
|
|
$notifyLibrary->setFrom( $memberData );
|
|
$notifyLibrary->setNotificationKey( 'invite_private_message' );
|
|
$notifyLibrary->setNotificationUrl( $this->registry->output->buildUrl( "app=members&module=messaging§ion=view&do=showConversation&topicID={$topicID}", 'public' ) );
|
|
$notifyLibrary->setNotificationText( IPSText::getTextClass('email')->message );
|
|
$notifyLibrary->setNotificationTitle( IPSText::getTextClass('email')->subject );
|
|
|
|
try
|
|
{
|
|
$notifyLibrary->sendNotification();
|
|
}
|
|
catch( Exception $e ){}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Delete personal topics
|
|
*
|
|
* @param int Owner Member ID
|
|
* @param array Array of IDs to delete
|
|
* @param string [ Raw SQL to query on when selecting messages to delete, optional ]
|
|
* @param bool Force hard delete
|
|
* @return mixed bool or exception
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* NO_SUCH_MEMBER: The member ID does not exist
|
|
* NO_IDS_TO_DELETE: No IDs to delete (empty id array)
|
|
* </code>
|
|
*/
|
|
public function deleteTopics( $memberID, $ids, $rawSQL=NULL, $hardDelete=false )
|
|
{
|
|
//-----------------------------------------
|
|
// Grab data
|
|
//-----------------------------------------
|
|
|
|
$memberData = IPSMember::load( $memberID, 'groups,extendedProfile' );
|
|
$final_ids = array();
|
|
$final_mts = array();
|
|
$starter = array();
|
|
$wanttoleave = array();
|
|
$participater = array();
|
|
$system = array();
|
|
$deleted_ids = array();
|
|
$attach_ids = array();
|
|
$toHardDelete = array();
|
|
$membahs = array( $memberID => $memberID );
|
|
|
|
if ( ! $memberData['member_id'] )
|
|
{
|
|
throw new Exception( "NO_SUCH_MEMBER");
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Check...
|
|
//-----------------------------------------
|
|
|
|
if ( ! is_array( $ids ) OR ! count( $ids ) )
|
|
{
|
|
throw new Exception("NO_IDS_TO_DELETE");
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Finish raw SQL
|
|
//-----------------------------------------
|
|
|
|
if ( $rawSQL !== NULL )
|
|
{
|
|
$rawSQL = ' AND ' . $rawSQL;
|
|
}
|
|
|
|
$idString = implode( ",", IPSLib::cleanIntArray( $ids ) );
|
|
|
|
//-----------------------------------------
|
|
// Grab all affected members...
|
|
//-----------------------------------------
|
|
|
|
$this->DB->build( array( 'select' => '*',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => 'map_topic_id IN(' . $idString . ')' ) );
|
|
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
$membahs[ $row['map_user_id'] ] = $row['map_user_id'];
|
|
}
|
|
|
|
/* Flag for recount */
|
|
$this->_flagForCountReset( $membahs );
|
|
|
|
//-----------------------------------------
|
|
// Get messages?
|
|
//-----------------------------------------
|
|
|
|
$this->DB->build( array( 'select' => 'mt.*',
|
|
'from' => array( 'message_topics' => 'mt' ),
|
|
'where' => "mt.mt_id IN(" . $idString . ")" . $rawSQL,
|
|
'add_join' => array( array( 'select' => 'map.*',
|
|
'from' => array( 'message_topic_user_map' => 'map' ),
|
|
'where' => 'map.map_topic_id=mt.mt_id AND map.map_user_id=' . $memberData['member_id'],
|
|
'type' => 'left' ) ) ) );
|
|
$this->DB->execute();
|
|
|
|
/* Build up topics to remove */
|
|
while ( $i = $this->DB->fetch() )
|
|
{
|
|
/* Starter? */
|
|
if ( $i['mt_starter_id'] == $memberData['member_id'] )
|
|
{
|
|
$starter[ $i['mt_id'] ] = $i;
|
|
$allTopics[ $i['mt_id'] ] = $i;
|
|
}
|
|
else if ( $i['map_user_id'] AND $i['mt_is_system'] )
|
|
{
|
|
$system[ $i['mt_id'] ] = $i;
|
|
$allTopics[ $i['mt_id'] ] = $i;
|
|
}
|
|
else if ( $i['map_user_id'] )
|
|
{
|
|
$wanttoleave[ $i['mt_id'] ] = $i;
|
|
$allTopics[ $i['mt_id'] ] = $i;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Are we forcing a hard delete
|
|
//-----------------------------------------
|
|
|
|
if( $hardDelete )
|
|
{
|
|
$idsForAttachments = array();
|
|
|
|
$this->DB->build( array( 'select' => 'msg_id',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_topic_id IN ('. $idString . ')'
|
|
) );
|
|
$this->DB->execute();
|
|
|
|
while( $r = $this->DB->fetch() )
|
|
{
|
|
$idsForAttachments[] = $r['msg_id'];
|
|
}
|
|
|
|
/* Delete Topics */
|
|
$this->DB->delete( 'message_topics', 'mt_id IN ('. $idString . ')' . $rawSQL );
|
|
|
|
/* Delete Posts */
|
|
$this->DB->delete( 'message_posts', 'msg_topic_id IN ('. $idString . ')' . $rawSQL );
|
|
|
|
/* Delete mappings */
|
|
$this->DB->delete( 'message_topic_user_map', 'map_topic_id IN ('. $idString . ')' . $rawSQL );
|
|
|
|
//-----------------------------------------
|
|
// Delete attachments
|
|
//-----------------------------------------
|
|
|
|
$classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'core' ) . '/sources/classes/attach/class_attach.php', 'class_attach' );
|
|
$class_attach = new $classToLoad( $this->registry );
|
|
$class_attach->type = 'msg';
|
|
$class_attach->init();
|
|
$class_attach->bulkRemoveAttachment( $idsForAttachments );
|
|
}
|
|
else
|
|
{
|
|
//-----------------------------------------
|
|
// System PMs, delete everything to do with them
|
|
//-----------------------------------------
|
|
|
|
if ( count( $system ) )
|
|
{
|
|
/* Delete Topics */
|
|
$this->DB->delete( 'message_topics', 'mt_id IN ('. implode( ',', array_keys( $system ) ) . ')' );
|
|
|
|
/* Delete Posts */
|
|
$this->DB->delete( 'message_posts', 'msg_topic_id IN ('. implode( ',', array_keys( $system ) ) . ')' );
|
|
|
|
/* Delete mappings */
|
|
$this->DB->delete( 'message_topic_user_map', 'map_topic_id IN ('. implode( ',', array_keys( $system ) ) . ')' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Ones I started, soft delete
|
|
//-----------------------------------------
|
|
|
|
if ( count( $starter ) )
|
|
{
|
|
/* First step: Soft delete them */
|
|
$this->DB->update( 'message_topics', 'mt_to_count=mt_to_count-1,mt_is_deleted=1', 'mt_id IN (' . implode( ',', array_keys( $starter ) ) . ')', FALSE, TRUE );
|
|
|
|
/* Update mappings for member */
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_user_active' => 0 ), 'map_user_id=' . $memberData['member_id'] . ' AND map_topic_id IN ('. implode( ',', array_keys( $starter ) ) . ')' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Ones that I just want to leave..
|
|
//-----------------------------------------
|
|
|
|
if ( count( $wanttoleave ) )
|
|
{
|
|
/* De-activate participant row */
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_user_active' => 0 ), 'map_user_id=' . $memberData['member_id'] . ' AND map_topic_id IN ('. implode( ',', array_keys( $wanttoleave ) ) . ')' );
|
|
|
|
/* Update counts */
|
|
$this->DB->update( 'message_topics', 'mt_to_count=mt_to_count-1', 'mt_id IN (' . implode( ',', array_keys( $wanttoleave ) ) . ')', FALSE, TRUE );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Right. Now lets find all (partici)pantless topics
|
|
//-----------------------------------------
|
|
|
|
if ( count( $allTopics ) )
|
|
{
|
|
$this->DB->build( array( 'select' => 'mt.*',
|
|
'from' => array( 'message_topics' => 'mt' ),
|
|
'where' => "mt.mt_id IN(" . implode( ',', array_keys( $allTopics ) ) . ")",
|
|
'add_join' => array( array( 'select' => 'map.*',
|
|
'from' => array( 'message_topic_user_map' => 'map' ),
|
|
'where' => 'map.map_topic_id=mt.mt_id AND map.map_user_active=1',
|
|
'type' => 'left' ) ) ) );
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
/* Not got -any- mapping? */
|
|
if ( ! $row['map_user_id'] )
|
|
{
|
|
$toHardDelete[ $row['mt_id'] ] = $row;
|
|
}
|
|
}
|
|
|
|
$idsForAttachments = array();
|
|
|
|
$this->DB->build( array( 'select' => 'msg_id',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_topic_id IN ('. implode( ',', array_keys( $allTopics ) ) . ')'
|
|
) );
|
|
$this->DB->execute();
|
|
|
|
while( $r = $this->DB->fetch() )
|
|
{
|
|
$idsForAttachments[] = $r['msg_id'];
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Hard delete MT topics
|
|
//-----------------------------------------
|
|
|
|
if ( count($toHardDelete) )
|
|
{
|
|
$this->DB->delete( 'message_topics', "mt_id IN (".implode( ',', array_keys( $toHardDelete ) ).")" );
|
|
|
|
//-----------------------------------------
|
|
// Delete attachments
|
|
//-----------------------------------------
|
|
|
|
$classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'core' ) . '/sources/classes/attach/class_attach.php', 'class_attach' );
|
|
$class_attach = new $classToLoad( $this->registry );
|
|
$class_attach->type = 'msg';
|
|
$class_attach->init();
|
|
$class_attach->bulkRemoveAttachment( array_keys( $idsForAttachments ) );
|
|
|
|
//-----------------------------------------
|
|
// Delete posts and mapping
|
|
//-----------------------------------------
|
|
|
|
$this->DB->delete( 'message_posts', 'msg_topic_id IN (' . implode( ',', array_keys( $toHardDelete ) ) . ')' );
|
|
$this->DB->delete( 'message_topic_user_map', 'map_topic_id IN (' . implode( ',', array_keys( $toHardDelete ) ) . ')' );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Moves messages into another folder
|
|
*
|
|
* @param int Owner Member ID
|
|
* @param array Array of IDs to move
|
|
* @param string 'id' of folder to move to
|
|
* @return mixed bool or exception
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* NO_SUCH_MEMBER: The member ID does not exist
|
|
* NO_SUCH_FOLDER: Folder you are attemting to move to does not exist
|
|
* NO_IDS_TO_MOVE No IDs to move (empty id array)
|
|
* </code>
|
|
*/
|
|
public function moveTopics( $memberID, $ids, $toFolderID )
|
|
{
|
|
//-----------------------------------------
|
|
// Grab data
|
|
//-----------------------------------------
|
|
|
|
$memberData = IPSMember::load( $memberID, 'groups,extendedProfile' );
|
|
|
|
if ( ! $memberData['member_id'] )
|
|
{
|
|
throw new Exception( "NO_SUCH_MEMBER");
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Check...
|
|
//-----------------------------------------
|
|
|
|
if ( ! is_array( $ids ) OR ! count( $ids ) )
|
|
{
|
|
throw new Exception("NO_IDS_TO_MOVE");
|
|
}
|
|
|
|
$idString = implode( ",", $ids );
|
|
|
|
//-----------------------------------------
|
|
// First off, get dir data
|
|
//-----------------------------------------
|
|
|
|
$folders = $this->explodeFolderData( $memberData['pconversation_filters'] );
|
|
|
|
//-----------------------------------------
|
|
// Got a folder with that ID?
|
|
//-----------------------------------------
|
|
|
|
if ( ! $folders[ $toFolderID ] )
|
|
{
|
|
throw new Exception("NO_SUCH_FOLDER");
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Move the messages...
|
|
//-----------------------------------------
|
|
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_folder_id' => $toFolderID ), "map_user_id=".$memberData['member_id']." AND map_topic_id IN ($idString)" );
|
|
|
|
/* Recount */
|
|
$this->resetMembersFolderCounts( $memberData['member_id'] );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Edits a message
|
|
*
|
|
* @param int FROM Member ID
|
|
* @param int Topic ID
|
|
* @param int Msg ID
|
|
* @param string Message Content
|
|
* @return mixed TRUE or FALSE or Exception
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* MSG_CONTENT_EMPTY: The 'msgContent' varable is empty
|
|
* NO_SUCH_TOPIC: No such topic was found
|
|
* NO_PERMISSION: No permission to read/reply
|
|
* NO_EDIT_PERMISSION: No permission to edit
|
|
* TOPIC_HAS_BEEN_DELETED: Topic has been "deleted" by the topic starter
|
|
* </code>
|
|
*/
|
|
public function sendEdit( $fromMemberID, $topicID, $msgID, $msgContent, $options=array() )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$topicData = array();
|
|
$messageData = array();
|
|
$fromMemberData = array();
|
|
$remapData = array();
|
|
|
|
//-----------------------------------------
|
|
// Check content
|
|
//-----------------------------------------
|
|
|
|
if ( ! $msgContent )
|
|
{
|
|
throw new Exception( 'MSG_CONTENT_EMPTY' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Format content
|
|
//-----------------------------------------
|
|
|
|
try
|
|
{
|
|
$msgContent = $this->_formatMessageForSaving( $msgContent );
|
|
}
|
|
catch( Exception $error )
|
|
{
|
|
throw new Exception( $error->getMessage() );
|
|
}
|
|
|
|
/* Fetch topic data */
|
|
$topicData = $this->DB->buildAndFetch( array( 'select' => '*',
|
|
'from' => 'message_topics',
|
|
'where' => 'mt_id=' . $topicID ) );
|
|
|
|
if ( ! $topicData['mt_id'] )
|
|
{
|
|
throw new Exception( 'NO_SUCH_TOPIC' );
|
|
}
|
|
|
|
if ( $topicData['mt_is_deleted'] )
|
|
{
|
|
throw new Exception( 'TOPIC_HAS_BEEN_DELETED' );
|
|
}
|
|
|
|
/* Fetch remap Data */
|
|
$this->DB->build( array( 'select' => '*',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => 'map_topic_id=' . $topicID ) );
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
$remapData[ $row['map_user_id'] ] = $row;
|
|
}
|
|
|
|
/* Got us? */
|
|
if ( $this->canAccessTopic( $fromMemberID, $topicData ) !== TRUE )
|
|
{
|
|
throw new Exception( "NO_PERMISSION" );
|
|
}
|
|
|
|
/* Fetch message data */
|
|
$messageData = $this->fetchMessageData( $topicID, $msgID );
|
|
|
|
/* Reset Post Key */
|
|
$options['postKey'] = ( $messageData['msg_post_key'] ) ? $messageData['msg_post_key'] : md5(microtime());
|
|
|
|
//-----------------------------------------
|
|
// Load member data
|
|
//-----------------------------------------
|
|
|
|
$memberData = IPSMember::load( array_keys( $remapData ), 'groups,extendedProfile' );
|
|
$fromMemberData = $memberData[ $fromMemberID ];
|
|
|
|
/* Can edit? */
|
|
if ( $topicData['mt_is_deleted'] OR $this->_conversationCanEdit( $messageData, $topicData, $fromMemberData ) !== TRUE )
|
|
{
|
|
throw new Exception( "NO_EDIT_PERMISSION" );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Update the post...
|
|
//-----------------------------------------
|
|
|
|
$this->DB->update( 'message_posts', array( 'msg_post' => $msgContent ), 'msg_id=' . $msgID );
|
|
|
|
/* Fetch attachment count */
|
|
$count = intval( $this->_makeAttachmentsPermanent( $options['postKey'], $msgID, $topicID ) );
|
|
|
|
if ( $count )
|
|
{
|
|
$this->DB->update( 'message_topics', array( 'mt_hasattach' => $count ), 'mt_id=' . $topicID );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Sends a reply to a PM
|
|
*
|
|
* @param int FROM Member ID
|
|
* @param int Topic ID
|
|
* @param string Message Content
|
|
* @return mixed Msg ID or exception
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* MSG_CONTENT_EMPTY: The 'msgContent' varable is empty
|
|
* NO_SUCH_TOPIC: No such topic was found
|
|
* NO_PERMISSION: No permission to read/reply
|
|
* TOPIC_HAS_BEEN_DELETED: Topic has been "deleted" by the topic starter
|
|
* TOPIC_IS_SYSTEM: This is a system topic and cannot be replied to
|
|
* FROM_USER_BLOCKED: Cannot send as starter has blocked fromMemberID
|
|
* </code>
|
|
*/
|
|
public function sendReply( $fromMemberID, $topicID, $msgContent, $options=array() )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$topicData = array();
|
|
$fromMemberData = array();
|
|
$remapData = array();
|
|
|
|
$options['postKey'] = ( $options['postKey'] ) ? $options['postKey'] : md5(microtime());
|
|
|
|
//-----------------------------------------
|
|
// Check content
|
|
//-----------------------------------------
|
|
|
|
if ( ! $msgContent )
|
|
{
|
|
throw new Exception( 'MSG_CONTENT_EMPTY' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Format content
|
|
//-----------------------------------------
|
|
|
|
try
|
|
{
|
|
$msgContent = $this->_formatMessageForSaving( $msgContent );
|
|
}
|
|
catch( Exception $error )
|
|
{
|
|
throw new Exception( $error->getMessage() );
|
|
}
|
|
|
|
/* Fetch topic data */
|
|
$topicData = $this->DB->buildAndFetch( array( 'select' => '*',
|
|
'from' => 'message_topics',
|
|
'where' => 'mt_id=' . $topicID ) );
|
|
|
|
if ( ! $topicData['mt_id'] )
|
|
{
|
|
throw new Exception( 'NO_SUCH_TOPIC' );
|
|
}
|
|
|
|
if ( $topicData['mt_is_deleted'] )
|
|
{
|
|
throw new Exception( 'TOPIC_HAS_BEEN_DELETED' );
|
|
}
|
|
|
|
if ( $topicData['mt_is_system'] )
|
|
{
|
|
throw new Exception( 'TOPIC_IS_SYSTEM' );
|
|
}
|
|
|
|
/* Fetch remap Data */
|
|
$this->DB->build( array( 'select' => '*',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => 'map_user_active=1 AND map_topic_id=' . $topicID ) );
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
$remapData[ $row['map_user_id'] ] = $row;
|
|
}
|
|
|
|
/* Got us? */
|
|
if ( ! isset($remapData[ $fromMemberID ]) )
|
|
{
|
|
throw new Exception( "NO_PERMISSION" );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Load member data
|
|
//-----------------------------------------
|
|
|
|
$memberData = IPSMember::load( array_keys( $remapData ), 'groups,extendedProfile' );
|
|
$fromMemberData = $memberData[ $fromMemberID ];
|
|
|
|
//-----------------------------------------
|
|
// Has the 'to' use blocked us?
|
|
//-----------------------------------------
|
|
|
|
if ( count( $this->blockedByUser( $fromMemberData, $topicData['mt_to_member_id'] ) ) )
|
|
{
|
|
if ( $this->forceMessageToSend !== TRUE )
|
|
{
|
|
$this->exceptionData = array( 0 => $memberData[ $topicData['mt_to_member_id'] ]['members_display_name'] );
|
|
|
|
throw new Exception( 'FROM_USER_BLOCKED' );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Add the post...
|
|
//-----------------------------------------
|
|
|
|
$_messagePostData = array(
|
|
'msg_date' => time(),
|
|
'msg_topic_id' => $topicID,
|
|
'msg_post' => $msgContent,
|
|
'msg_post_key' => md5( microtime() ),
|
|
'msg_author_id' => $fromMemberData['member_id'],
|
|
'msg_ip_address' => $this->member->ip_address
|
|
);
|
|
|
|
/* Data Hook Location */
|
|
IPSLib::doDataHooks( $_messagePostData, 'messengerSendReplyData' );
|
|
|
|
$this->DB->insert( 'message_posts', $_messagePostData );
|
|
|
|
$msg_id = $this->DB->getInsertId();
|
|
|
|
//-----------------------------------------
|
|
// Update topic
|
|
//-----------------------------------------
|
|
|
|
$replyCount = $this->DB->buildAndFetch( array( 'select' => 'count(*) as count',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_topic_id=' . $topicID ) );
|
|
|
|
$replyCount['count'] = ( $replyCount['count'] > 0 ) ? $replyCount['count'] - 1 : 0;
|
|
|
|
$this->DB->update( 'message_topics', array( 'mt_last_post_time' => IPS_UNIX_TIME_NOW,
|
|
'mt_hasattach' => ($topicData['mt_hasattach'] + intval( $this->_makeAttachmentsPermanent( $options['postKey'], $msg_id, $topicID ) )),
|
|
'mt_replies' => intval( $replyCount['count'] ),
|
|
'mt_last_msg_id' => $msg_id ), 'mt_id=' . $topicID );
|
|
|
|
/* Update mapping */
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_has_unread' => 1 ), 'map_topic_id=' . $topicID . ' AND map_user_id != ' . $fromMemberID );
|
|
|
|
/* Update last reply time */
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_last_topic_reply' => IPS_UNIX_TIME_NOW ), 'map_topic_id=' . $topicID );
|
|
|
|
//-----------------------------------------
|
|
// Update receipients....
|
|
//-----------------------------------------
|
|
|
|
foreach ($remapData as $memberID => $_remapData )
|
|
{
|
|
$toMember = $memberData[ $memberID ];
|
|
|
|
//-----------------------------------------
|
|
// Disabled messenger
|
|
//-----------------------------------------
|
|
|
|
if( $toMember['members_disable_pm'] )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Let them know there's a new PM reply
|
|
//-----------------------------------------
|
|
|
|
if ( $memberID != $fromMemberID )
|
|
{
|
|
/**
|
|
* @link http://community.invisionpower.com/tracker/issue-37272-pm-notification-counter-not-increasing/page__catfilter__1
|
|
*/
|
|
/*if ( $_remapData['map_ignore_notification'] )
|
|
{
|
|
IPSMember::save( $memberID, array( 'core' => array( 'msg_count_reset' => 1 ) ) );
|
|
}
|
|
else
|
|
{
|
|
IPSMember::save( $memberID, array( 'core' => array( 'msg_count_new' => intval( $this->getPersonalTopicsCount( $memberID, 'new' ) ),
|
|
'msg_count_reset' => 1 ) ) );
|
|
}*/
|
|
if ( empty($_remapData['map_ignore_notification']) && empty($_remapData['map_has_unread']) )
|
|
{
|
|
IPSMember::save( $memberID, array( 'core' => array( 'msg_count_new' => 'plus:1' ) ) );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Notifications library
|
|
//-----------------------------------------
|
|
|
|
if ( $memberID != $fromMemberID AND ! $_remapData['map_ignore_notification'] )
|
|
{
|
|
$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . '/sources/classes/member/notifications.php', 'notifications' );
|
|
$notifyLibrary = new $classToLoad( $this->registry );
|
|
|
|
IPSText::getTextClass('email')->getTemplate( "personal_convo_new_reply", $toMember['language'] );
|
|
|
|
IPSText::getTextClass('email')->buildMessage( array( 'NAME' => $toMember['members_display_name'],
|
|
'POSTER' => $fromMemberData['members_display_name'],
|
|
'TITLE' => $topicData['mt_title'],
|
|
'TEXT' => $msgContent,
|
|
'LINK' => "?app=members&module=messaging§ion=view&do=findMessage&topicID={$topicID}&msgID=__firstUnread__" ) );
|
|
|
|
IPSText::getTextClass('email')->subject = sprintf( IPSText::getTextClass('email')->subject,
|
|
$this->registry->output->buildSEOUrl( 'showuser=' . $fromMemberData['member_id'], 'public', $fromMemberData['members_seo_name'], 'showuser' ),
|
|
$fromMemberData['members_display_name'],
|
|
$this->registry->output->buildUrl( "app=members&module=messaging§ion=view&do=findMessage&topicID={$topicID}&msgID=__firstUnread__", 'public' )
|
|
);
|
|
|
|
$notifyLibrary->setMember( $toMember );
|
|
$notifyLibrary->setFrom( $fromMemberData );
|
|
$notifyLibrary->setNotificationKey( 'reply_private_message' );
|
|
$notifyLibrary->setNotificationUrl( $this->registry->output->buildUrl( "app=members&module=messaging§ion=view&do=findMessage&topicID={$topicID}&msgID=__firstUnread__", 'public' ) );
|
|
$notifyLibrary->setNotificationText( IPSText::getTextClass('email')->message );
|
|
$notifyLibrary->setNotificationTitle( IPSText::getTextClass('email')->subject );
|
|
$notifyLibrary->setMetaData( array( 'meta_area' => 'pm', 'meta_id' => $topicID, 'meta_app' => 'members' ) );
|
|
|
|
try
|
|
{
|
|
$notifyLibrary->sendNotification();
|
|
}
|
|
catch( Exception $e ){}
|
|
}
|
|
}
|
|
|
|
return $msg_id;
|
|
}
|
|
|
|
/**
|
|
* Sends a new personal message. Very simple.
|
|
*
|
|
* @param int TO Member ID
|
|
* @param int FROM Member ID
|
|
* @param array Array of InviteUser Names (display name)
|
|
* @param string Message Title
|
|
* @param string Message Content
|
|
* @param array Options array[ 'isSystem' (if true, then user will have no record of sending this PM) postKey, 'isDraft', 'sendMode' (invite/copy), 'topicID' ] If a topicID is passed, it's presumed that it was a draft....
|
|
* @return mixed TRUE or FALSE or Exception
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* TOPIC_ID_NOT_EXISTS: Topic ID does not exist (re-sending a draft)
|
|
* NOT_ALL_INVITE_USERS_EXIST: Not all invite users exist (check $this->exceptionData for a list of names)
|
|
* NOT_ALL_INVITE_USERS_CAN_PM: Not all invite users can PM (check $this->exceptionData for a list of names)
|
|
* INVITE_USERS_BLOCKED: Some invite users have been blocked (check $this->exceptionData for a list of names)
|
|
* TO_USER_DOES_NOT_EXIST: The 'to' user ID does not exist
|
|
* FROM_USER_DOES_NOT_EXIST: The 'from' user ID does not exist
|
|
* TO_USER_CANNOT_USE_PM: The 'to' user does not have access to PM system
|
|
* TO_USER_FULL: The 'to' user cannot accept any more PMs (inbox full)
|
|
* FROM_USER_BLOCKED: The 'from' user has been blocked by the 'to' user
|
|
* CANNOT_SAVE_TO_SENT_FOLDER: The 'from' user does not have space to store a copy of the message in their sent folder
|
|
* MSG_TITLE_EMPTY: The 'msgTitle' variable is empty
|
|
* MSG_CONTENT_EMPTY: The 'msgContent' varable is empty
|
|
* CANT_SEND_TO_SELF: The main recipient and sender are the same
|
|
* CANT_INVITE_SELF: The sender is in the invite list
|
|
* CANT_INVITE_RECIPIENT: The main recipient is in the invite list
|
|
* FLOOD_STOP Flood control will not allow this message to send
|
|
* </code>
|
|
*/
|
|
public function sendNewPersonalTopic( $toMemberID, $fromMemberID, $inviteUsers, $msgTitle, $msgContent, $options=array() )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$toMemberData = array();
|
|
$fromMemberData = array();
|
|
$inviteUsersData = array();
|
|
$isDraft = ( $options['isDraft'] ) ? TRUE : FALSE;
|
|
$isCopyTo = ( $options['sendMode'] == 'copy' ) ? TRUE : FALSE;
|
|
$isSystem = ( $options['isSystem'] === TRUE || $options['isSystem'] == 1 ) ? 1 : 0;
|
|
$options['postKey'] = ( $options['postKey'] ) ? $options['postKey'] : md5(microtime());
|
|
|
|
/* Set up force message*/
|
|
$this->forceMessageToSend = ( $this->forceMessageToSend ) ? $this->forceMessageToSend : ( ( $options['forcePm'] ) ? TRUE : FALSE );
|
|
|
|
//-----------------------------------------
|
|
// Check content
|
|
//-----------------------------------------
|
|
|
|
if ( $toMemberID == $fromMemberID )
|
|
{
|
|
throw new Exception( 'CANT_SEND_TO_SELF' );
|
|
}
|
|
|
|
if ( ! $msgTitle )
|
|
{
|
|
throw new Exception( 'MSG_TITLE_EMPTY' );
|
|
}
|
|
|
|
if ( ! $msgContent )
|
|
{
|
|
throw new Exception( 'MSG_CONTENT_EMPTY' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Format content
|
|
//-----------------------------------------
|
|
|
|
try
|
|
{
|
|
$_originalMessageContent = $msgContent;
|
|
$msgContent = $this->_formatMessageForSaving( $msgContent );
|
|
}
|
|
catch( Exception $error )
|
|
{
|
|
throw new Exception( $error->getMessage() );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// First off, load the to and from members
|
|
//-----------------------------------------
|
|
|
|
$_members = IPSMember::load( array( $toMemberID, $fromMemberID ), 'groups,extendedProfile' );
|
|
|
|
$toMemberData = $this->_setMaxMessages( $_members[ $toMemberID ] );
|
|
$fromMemberData = $this->_setMaxMessages( $_members[ $fromMemberID ] );
|
|
|
|
if ( empty( $toMemberData['member_id'] ) AND $this->forceMessageToSend !== TRUE )
|
|
{
|
|
throw new Exception( 'TO_USER_DOES_NOT_EXIST' );
|
|
}
|
|
|
|
if ( empty( $fromMemberData['member_id'] ) AND $this->forceMessageToSend !== TRUE )
|
|
{
|
|
throw new Exception( 'FROM_USER_DOES_NOT_EXIST' );
|
|
}
|
|
|
|
if ( $this->floodControlCheck() !== TRUE )
|
|
{
|
|
throw new Exception( 'FLOOD_STOP' );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Sort out invite users
|
|
//-----------------------------------------
|
|
|
|
if ( is_array( $inviteUsers ) AND count( $inviteUsers ) )
|
|
{
|
|
try
|
|
{
|
|
if ( $fromMemberData['g_max_mass_pm'] > 0 OR $this->forceMessageToSend === TRUE )
|
|
{
|
|
$inviteUsersData = $this->checkAndReturnInvitedUsers( $inviteUsers );
|
|
}
|
|
}
|
|
catch( Exception $error )
|
|
{
|
|
if ( $this->forceMessageToSend !== TRUE )
|
|
{
|
|
throw new Exception( $error->getMessage() );
|
|
}
|
|
}
|
|
|
|
if ( isset($inviteUsersData[ $fromMemberID ]) )
|
|
{
|
|
throw new Exception( 'CANT_INVITE_SELF' );
|
|
}
|
|
|
|
if ( isset($inviteUsersData[ $toMemberID ]) )
|
|
{
|
|
throw new Exception( 'CANT_INVITE_RECIPIENT' );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Can the 'to' user accept a PM?
|
|
//-----------------------------------------
|
|
|
|
if ( $this->canUsePMSystem( $toMemberData ) !== TRUE )
|
|
{
|
|
if ( $this->forceMessageToSend !== TRUE )
|
|
{
|
|
throw new Exception( 'TO_USER_CANNOT_USE_PM' );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Does the 'to' user have enough space?
|
|
//-----------------------------------------
|
|
|
|
if ( $this->withinPMQuota( $toMemberData ) !== TRUE )
|
|
{
|
|
if ( $this->forceMessageToSend !== TRUE )
|
|
{
|
|
throw new Exception( 'TO_USER_FULL' );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Has the 'to' use blocked us?
|
|
//-----------------------------------------
|
|
|
|
if ( count( $this->blockedByUser( $fromMemberData, $toMemberData ) ) )
|
|
{
|
|
if ( $this->forceMessageToSend !== TRUE )
|
|
{
|
|
throw new Exception( 'FROM_USER_BLOCKED' );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Is this simply a copy-to?
|
|
//-----------------------------------------
|
|
|
|
if ( $isCopyTo === TRUE AND !$isDraft )
|
|
{
|
|
/* Send out the main one */
|
|
$this->sendNewPersonalTopic( $toMemberID, $fromMemberID, array(), $msgTitle, $_originalMessageContent, array( 'postKey' => $options['postKey'] ) );
|
|
|
|
/* Send out copy-tos */
|
|
foreach ($inviteUsersData as $id => $toMember)
|
|
{
|
|
$_newPostKey = md5( microtime() );
|
|
$_newContent = $_originalMessageContent;
|
|
|
|
/* We need to duplicate the attachment record for each copy sent */
|
|
$this->DB->build( array( 'select' => '*', 'from' => 'attachments', 'where' => "attach_post_key='{$options['postKey']}'" ) );
|
|
$outer = $this->DB->execute();
|
|
|
|
$idRemap = array();
|
|
|
|
while( $attachData = $this->DB->fetch($outer) )
|
|
{
|
|
$attachData['attach_post_key'] = $_newPostKey;
|
|
$_oldAttachId = $attachData['attach_id'];
|
|
unset( $attachData['attach_id'] );
|
|
|
|
$this->DB->insert( 'attachments', $attachData );
|
|
|
|
$idRemap[ $_oldAttachId ] = $this->DB->getInsertId();
|
|
}
|
|
|
|
if( count($idRemap) )
|
|
{
|
|
foreach( $idRemap as $_oldId => $_newId )
|
|
{
|
|
$_newContent = str_replace( '=' . $_oldId . ':', '=' . $_newId . ':', $_newContent );
|
|
}
|
|
}
|
|
|
|
$this->sendNewPersonalTopic( $toMember['member_id'], $fromMemberID, array(), $msgTitle, $_newContent, array( 'postKey' => $_newPostKey ) );
|
|
}
|
|
|
|
/* Done */
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Insert the user data
|
|
//-----------------------------------------
|
|
|
|
$_count = count( $inviteUsersData );
|
|
|
|
//-----------------------------------------
|
|
// Got a topic ID?
|
|
//-----------------------------------------
|
|
|
|
if ( $options['topicID'] )
|
|
{
|
|
/* Fetch topic data */
|
|
$_topicData = $this->fetchTopicData( $options['topicID'] );
|
|
|
|
if ( ! $_topicData['mt_id'] AND $this->forceMessageToSend !== TRUE )
|
|
{
|
|
throw new Exception( 'TOPIC_ID_NOT_EXISTS' );
|
|
}
|
|
|
|
$this->DB->setDataType( 'mt_title', 'string' );
|
|
|
|
/* First off, update message_topics and message_posts... */
|
|
$this->DB->update( 'message_topics', array( 'mt_date' => time(),
|
|
'mt_title' => $msgTitle,
|
|
'mt_starter_id' => $fromMemberData['member_id'],
|
|
'mt_start_time' => time(),
|
|
'mt_last_post_time' => time(),
|
|
'mt_invited_members' => serialize( array_keys( $inviteUsersData ) ),
|
|
'mt_to_count' => count( array_keys( $inviteUsersData ) ) + 1,
|
|
'mt_to_member_id' => $toMemberData['member_id'],
|
|
'mt_is_draft' => intval( $isDraft ) ), 'mt_id=' . $_topicData['mt_id'] );
|
|
|
|
/* Now the posts ... */
|
|
$this->DB->update( 'message_posts', array( 'msg_date' => time(),
|
|
'msg_topic_id' => $_topicData['mt_id'],
|
|
'msg_post' => $msgContent,
|
|
'msg_author_id' => $fromMemberData['member_id'],
|
|
'msg_is_first_post' => 1,
|
|
'msg_ip_address' => $this->member->ip_address ), 'msg_id=' . $_topicData['mt_first_msg_id'] );
|
|
|
|
/* Delete any current user mapping as this will be sorted out below */
|
|
$this->DB->delete( 'message_topic_user_map', 'map_topic_id=' . $_topicData['mt_id'] );
|
|
|
|
/* Reset variable IDs */
|
|
$msg_topic_id = $_topicData['mt_id'];
|
|
$msg_id = $_topicData['mt_first_msg_id'];
|
|
|
|
IPSMember::save( $toMemberData['member_id'], array( 'core' => array( 'msg_count_new' => 'plus:1' ) ) );
|
|
}
|
|
//-----------------------------------------
|
|
// Insert new...
|
|
//-----------------------------------------
|
|
else
|
|
{
|
|
$_messageTopicData = array(
|
|
'mt_date' => time(),
|
|
'mt_title' => $msgTitle,
|
|
'mt_starter_id' => $fromMemberData['member_id'],
|
|
'mt_start_time' => IPS_UNIX_TIME_NOW,
|
|
'mt_last_post_time' => IPS_UNIX_TIME_NOW,
|
|
'mt_invited_members' => serialize( array_keys( $inviteUsersData ) ),
|
|
'mt_to_count' => count( array_keys( $inviteUsersData ) ) + 1,
|
|
'mt_to_member_id' => $toMemberData['member_id'],
|
|
'mt_is_draft' => ( $isDraft ) ? 1 : 0,
|
|
'mt_is_system' => $isSystem,
|
|
'mt_replies' => 0
|
|
);
|
|
|
|
/* Create topic entry */
|
|
$this->DB->setDataType( 'mt_title', 'string' );
|
|
|
|
/* Data Hook Location */
|
|
IPSLib::doDataHooks( $_messageTopicData, 'messengerSendTopicData' );
|
|
|
|
$this->DB->insert( 'message_topics', $_messageTopicData );
|
|
|
|
$msg_topic_id = $this->DB->getInsertId();
|
|
|
|
$_messagePostData = array(
|
|
'msg_date' => time(),
|
|
'msg_topic_id' => $msg_topic_id,
|
|
'msg_post' => $msgContent,
|
|
'msg_post_key' => $options['postKey'],
|
|
'msg_author_id' => $fromMemberData['member_id'],
|
|
'msg_is_first_post' => 1,
|
|
'msg_ip_address' => $this->member->ip_address
|
|
);
|
|
|
|
/* Data Hook Location */
|
|
IPSLib::doDataHooks( $_messagePostData, 'messengerSendTopicFirstPostData' );
|
|
|
|
$this->DB->insert( 'message_posts', $_messagePostData );
|
|
|
|
$msg_id = $this->DB->getInsertId();
|
|
|
|
if ( ! $isDraft )
|
|
{
|
|
IPSMember::save( $toMemberData['member_id'], array( 'core' => array( 'msg_count_new' => 'plus:1' ) ) );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Update with last / first msg ID
|
|
//-----------------------------------------
|
|
|
|
$this->DB->update( 'message_topics', array( 'mt_last_msg_id' => $msg_id,
|
|
'mt_first_msg_id' => $msg_id,
|
|
'mt_hasattach' => intval( $this->_makeAttachmentsPermanent( $options['postKey'], $msg_id, $msg_topic_id ) ) ), 'mt_id=' . $msg_topic_id );
|
|
|
|
//-----------------------------------------
|
|
// Not a draft?
|
|
//-----------------------------------------
|
|
|
|
if ( $isDraft !== TRUE )
|
|
{
|
|
//-----------------------------------------
|
|
// Add in 'to user' and 'from user' to the cc array
|
|
//-----------------------------------------
|
|
|
|
$inviteUsersData[ $toMemberData['member_id'] ] = $toMemberData;
|
|
$inviteUsersData[ $fromMemberData['member_id'] ] = $fromMemberData;
|
|
|
|
//-----------------------------------------
|
|
// Loop....
|
|
//-----------------------------------------
|
|
|
|
foreach( $inviteUsersData as $id => $toMember )
|
|
{
|
|
//-----------------------------------------
|
|
// Enter the info into the DB
|
|
// Target user side.
|
|
//-----------------------------------------
|
|
|
|
$_isStarter = ( $fromMemberData['member_id'] == $toMember['member_id'] ) ? 1 : 0;
|
|
$_isSystem = ( $fromMemberData['member_id'] == $toMember['member_id'] AND $isSystem ) ? 1 : 0;
|
|
$_isActive = ( $_isSystem ) ? 0 : 1;
|
|
|
|
/* Create user map entry */
|
|
$this->DB->insert( 'message_topic_user_map', array( 'map_user_id' => $toMember['member_id'],
|
|
'map_topic_id' => $msg_topic_id,
|
|
'map_folder_id' => 'myconvo',
|
|
'map_user_active' => $_isActive,
|
|
'map_is_starter' => ( $fromMemberData['member_id'] == $toMember['member_id'] ) ? 1 : 0,
|
|
'map_has_unread' => ( $fromMemberData['member_id'] == $toMember['member_id'] ) ? 0 : 1,
|
|
'map_read_time' => ( $fromMemberData['member_id'] == $toMember['member_id'] ) ? IPS_UNIX_TIME_NOW : 0,
|
|
'map_is_system' => $_isSystem,
|
|
'map_user_banned' => 0,
|
|
'map_left_time' => 0,
|
|
'map_ignore_notification' => 0,
|
|
'map_last_topic_reply' => IPS_UNIX_TIME_NOW ) );
|
|
|
|
//-----------------------------------------
|
|
// Update profile
|
|
//-----------------------------------------
|
|
|
|
/**
|
|
* @link http://community.invisionpower.com/tracker/issue-37272-pm-notification-counter-not-increasing/page__catfilter__1
|
|
*
|
|
* @todo This query can actually be moved outside the foreach cycle using an update IN array_keys()
|
|
*/
|
|
//IPSMember::save( $toMember['member_id'], array( 'core' => array( 'msg_count_total'=> 'plus:1', 'msg_count_reset' => 1 ) ) );
|
|
IPSMember::save( $toMember['member_id'], array( 'core' => array( 'msg_count_total'=> 'plus:1' ) ) );
|
|
|
|
//-----------------------------------------
|
|
// Notifications library
|
|
//-----------------------------------------
|
|
|
|
if ( $fromMemberData['member_id'] != $toMember['member_id'] )
|
|
{
|
|
$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . '/sources/classes/member/notifications.php', 'notifications' );
|
|
$notifyLibrary = new $classToLoad( $this->registry );
|
|
|
|
$toMember['language'] = $toMember['language'] == "" ? IPSLib::getDefaultLanguage() : $toMember['language'];
|
|
|
|
IPSText::getTextClass('email')->setPlainTextTemplate( IPSText::getTextClass('email')->getTemplate( 'personal_convo_new_convo', $toMember['language'] ) );
|
|
|
|
IPSText::getTextClass('email')->buildMessage( array(
|
|
'NAME' => $toMember['members_display_name'],
|
|
'POSTER' => $fromMemberData['members_display_name'],
|
|
'TITLE' => $msgTitle,
|
|
'TEXT' => $msgContent,
|
|
'LINK' => "?app=members&module=messaging§ion=view&do=showConversation&topicID={$msg_topic_id}#msg{$msg_id}" ) );
|
|
|
|
IPSText::getTextClass('email')->subject = sprintf(
|
|
IPSText::getTextClass('email')->subject,
|
|
$this->registry->output->buildSEOUrl( 'showuser=' . $fromMemberData['member_id'], 'public', $fromMemberData['members_seo_name'], 'showuser' ),
|
|
$fromMemberData['members_display_name'],
|
|
$this->registry->output->buildUrl( "app=members&module=messaging§ion=view&do=showConversation&topicID={$msg_topic_id}#msg{$msg_id}", 'public' )
|
|
);
|
|
|
|
$notifyLibrary->setMember( $toMember );
|
|
$notifyLibrary->setFrom( $fromMemberData );
|
|
$notifyLibrary->setNotificationKey( 'new_private_message' );
|
|
$notifyLibrary->setNotificationUrl( $this->registry->output->buildUrl( "app=members&module=messaging§ion=view&do=showConversation&topicID={$msg_topic_id}#msg{$msg_id}", 'public' ) );
|
|
$notifyLibrary->setNotificationText( IPSText::getTextClass('email')->getPlainTextContent() );
|
|
$notifyLibrary->setNotificationTitle( IPSText::getTextClass('email')->subject );
|
|
$notifyLibrary->setMetaData( array( 'meta_area' => 'pm', 'meta_id' => $msg_topic_id, 'meta_app' => 'members' ) );
|
|
try
|
|
{
|
|
$notifyLibrary->sendNotification();
|
|
}
|
|
catch( Exception $e ){}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//-----------------------------------------
|
|
// Is a draft
|
|
//-----------------------------------------
|
|
|
|
/* Create user map entry */
|
|
$this->DB->insert( 'message_topic_user_map', array( 'map_user_id' => $fromMemberData['member_id'],
|
|
'map_topic_id' => $msg_topic_id,
|
|
'map_folder_id' => 'drafts',
|
|
'map_user_active' => 1,
|
|
'map_has_unread' => 0,
|
|
'map_user_banned' => 0,
|
|
'map_read_time' => 0,
|
|
'map_left_time' => 0,
|
|
'map_ignore_notification' => 0,
|
|
'map_last_topic_reply' => IPS_UNIX_TIME_NOW ) );
|
|
|
|
if( ! $options['topicID'] )
|
|
{
|
|
//-----------------------------------------
|
|
// Update profile
|
|
//-----------------------------------------
|
|
|
|
$this->rebuildFolderCount( $fromMemberData['member_id'], array( 'drafts' => 'plus:1' ), TRUE, array( 'core' => array( 'msg_count_total' => 'plus:1' ) ) );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Delete messages from a topic
|
|
*
|
|
* @param array Array of message IDs to remove
|
|
* @param int Deleted by member ID
|
|
* @return boolean Deleted
|
|
*/
|
|
public function deleteMessages( $msgIDs=array(), $deletedByMemberID )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$idsToDelete = array();
|
|
$topics = array();
|
|
$unread = array();
|
|
$deletedByMember = IPSMember::load( intval( $deletedByMemberID ), 'all' );
|
|
|
|
//-----------------------------------------
|
|
// Check
|
|
//-----------------------------------------
|
|
|
|
if ( ! is_array( $msgIDs ) or ! count( $msgIDs ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Fetch all posts...
|
|
//-----------------------------------------
|
|
|
|
$this->DB->build( array( 'select' => 'msg.msg_id, msg.msg_topic_id, msg.msg_author_id',
|
|
'from' => array( 'message_posts' => 'msg' ),
|
|
'where' => 'msg.msg_id IN (' . implode( ',', IPSLib::cleanIntArray( $msgIDs ) ) . ') AND msg.msg_is_first_post != 1',
|
|
'add_join' => array( array( 'select' => 'mt.*',
|
|
'from' => array( 'message_topics' => 'mt' ),
|
|
'where' => 'mt.mt_id=msg.msg_topic_id',
|
|
'type' => 'left' ) ) ) );
|
|
|
|
$this->DB->execute();
|
|
|
|
while( $msg = $this->DB->fetch() )
|
|
{
|
|
if ( $this->_conversationCanDelete( $msg, $msg, $deletedByMember ) === TRUE )
|
|
{
|
|
$idsToDelete[ $msg['msg_id'] ] = $msg['msg_id'];
|
|
$topics[ $msg['msg_topic_id'] ] = $msg['msg_topic_id'];
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Got anything?
|
|
//-----------------------------------------
|
|
|
|
if ( ! count( $idsToDelete ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Is there an attachment to these messages??
|
|
//-----------------------------------------
|
|
|
|
$classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'core' ) . '/sources/classes/attach/class_attach.php', 'class_attach' );
|
|
$class_attach = new $classToLoad( $this->registry );
|
|
$class_attach->type = 'msg';
|
|
$class_attach->init();
|
|
$class_attach->bulkRemoveAttachment( $idsToDelete );
|
|
|
|
//-----------------------------------------
|
|
// Delete the messages
|
|
//-----------------------------------------
|
|
|
|
$this->DB->delete( 'message_posts', 'msg_id IN (' . implode( ',', IPSLib::cleanIntArray( $msgIDs ) ) . ')' );
|
|
|
|
//-----------------------------------------
|
|
// Rebuild member's new message count
|
|
// This MUST go before we rebuild the topic
|
|
// so we get all those who haven't yet read
|
|
// the last replies...
|
|
//-----------------------------------------
|
|
|
|
$this->DB->build( array( 'select' => '*',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => 'map_user_active=1 AND map_topic_id IN (' . implode( ",", array_keys( $topics ) ) . ') AND map_has_unread=1' ) );
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
$unread[ $row['map_user_id'] ] = $row['map_user_id'];
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Update all relevant topics
|
|
//-----------------------------------------
|
|
|
|
foreach( array_keys( $topics ) as $topicID )
|
|
{
|
|
$this->rebuildTopic( $topicID );
|
|
}
|
|
|
|
/* Update member counts */
|
|
if ( count( $unread ) )
|
|
{
|
|
$this->resetMembersNewTopicCount( $unread );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Rebuild a PM topic
|
|
*
|
|
* @param int Topic ID
|
|
* @return boolean
|
|
*/
|
|
public function rebuildTopic( $topicID )
|
|
{
|
|
//-----------------------------------------
|
|
// Get message count
|
|
//-----------------------------------------
|
|
|
|
$replyCount = $this->DB->buildAndFetch( array( 'select' => 'count(*) as count',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_topic_id=' . $topicID ) );
|
|
|
|
$replyCount['count'] = ( $replyCount['count'] > 0 ) ? $replyCount['count'] - 1 : 0;
|
|
|
|
//-----------------------------------------
|
|
// Fetch latest msg ID
|
|
//-----------------------------------------
|
|
|
|
$latestID = $this->DB->buildAndFetch( array( 'select' => 'msg_id, msg_date',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_topic_id=' . $topicID,
|
|
'order' => 'msg_date DESC',
|
|
'limit' => array( 0, 1 ) ) );
|
|
|
|
//-----------------------------------------
|
|
// Fetch first msg ID
|
|
//-----------------------------------------
|
|
|
|
$firstID = $this->DB->buildAndFetch( array( 'select' => 'msg_id, msg_date',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_topic_id=' . $topicID,
|
|
'order' => 'msg_date ASC',
|
|
'limit' => array( 0, 1 ) ) );
|
|
|
|
|
|
//-----------------------------------------
|
|
// Recount attachments
|
|
//-----------------------------------------
|
|
|
|
$attach = $this->DB->buildAndFetch( array(
|
|
'select' => 'COUNT(*) as attachments',
|
|
'from' => array( 'attachments' => 'a' ),
|
|
'where' => 'm.msg_topic_id=' . $topicID . " AND a.attach_rel_module='msg'",
|
|
'add_join' => array(
|
|
array( 'from' => array( 'message_posts' => 'm' ),
|
|
'where' => 'm.msg_id=a.attach_rel_id'
|
|
)
|
|
)
|
|
) );
|
|
|
|
//-----------------------------------------
|
|
// Update...
|
|
//-----------------------------------------
|
|
|
|
$this->DB->update( 'message_posts', array( 'msg_is_first_post' => 1 ), 'msg_id=' . $firstID['msg_id'] );
|
|
|
|
$this->DB->update( 'message_topics', array( 'mt_last_post_time' => $latestID['msg_date'],
|
|
'mt_replies' => intval( $replyCount['count'] ),
|
|
'mt_last_msg_id' => $latestID['msg_id'],
|
|
'mt_hasattach' => intval($attach['attachments']),
|
|
'mt_first_msg_id' => $firstID['msg_id'] ), 'mt_id=' . $topicID );
|
|
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_last_topic_reply' => $latestID['msg_date'] ), 'map_topic_id=' . $topicID );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Generate a 'definitive" list of invite users from an array of names
|
|
*
|
|
* @param array Array of display names [ 'bob', 'joe', 'dave' ]
|
|
* @param array Optional[ Array of member data (group + core only required) ]
|
|
* @param int Number of existing participants
|
|
* @return array Array of members, indexed by member_id
|
|
*
|
|
* <code>
|
|
* Exception Codes:
|
|
* NOT_ALL_INVITE_USERS_EXIST: Not all invite users exist (check $this->exceptionData for a list of names)
|
|
* NOT_ALL_INVITE_USERS_CAN_PM: Not all invite users can PM (check $this->exceptionData for a list of names)
|
|
* INVITE_USERS_BLOCKED: Some invite users have been blocked (check $this->exceptionData for a list of names)
|
|
* </code>
|
|
*/
|
|
public function checkAndReturnInvitedUsers( $names, $member=array(), $current=0 )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$finalArray = array();
|
|
$inviteArrayByID = array();
|
|
$inviteArrayByName = array();
|
|
$member = ( $member['member_id'] ) ? $member : $this->member->fetchMemberData();
|
|
$doesNotExist = array();
|
|
$cannotUsePM = array();
|
|
$current = intval($current);
|
|
|
|
if ( ! is_array( $names ) OR ! count( $names ) )
|
|
{
|
|
return $finalArray;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Get the members
|
|
//-----------------------------------------
|
|
|
|
$_members = IPSMember::load( $names, 'groups,extendedProfile', 'displayname' );
|
|
|
|
if ( ! is_array( $_members ) OR ! count( $_members ) )
|
|
{
|
|
return $finalArray;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Go Loopy
|
|
//-----------------------------------------
|
|
|
|
foreach( $_members as $member_id => $_member )
|
|
{
|
|
$inviteArrayByID[ $_member['member_id'] ] = $_member;
|
|
$inviteArrayByName[ $_member['members_l_display_name'] ] = $_member['member_id'];
|
|
|
|
# Only allow the first X based on g_max_mass_pm
|
|
if ( count( $inviteArrayByID ) + $current > $member['g_max_mass_pm'] )
|
|
{
|
|
throw new Exception( "MAX_USER_PM_LIMIT_HIT" );
|
|
break;
|
|
}
|
|
|
|
/* Hard limit of 500 */
|
|
if( count( $inviteArrayByID ) > 500 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Go loopy again...
|
|
//-----------------------------------------
|
|
|
|
foreach( $names as $name )
|
|
{
|
|
//-----------------------------------------
|
|
// Check to make sure all invite users exist
|
|
//-----------------------------------------
|
|
|
|
if ( ! in_array( strtolower( $name ), array_keys( $inviteArrayByName ) ) )
|
|
{
|
|
$doesNotExist[] = $name;
|
|
}
|
|
}
|
|
|
|
if ( count( $doesNotExist ) )
|
|
{
|
|
$this->exceptionData = $doesNotExist;
|
|
throw new Exception( "NOT_ALL_INVITE_USERS_EXIST" );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Check the block list..
|
|
//-----------------------------------------
|
|
|
|
$blockedInvitedUsers = $this->blockedByUser( $member, array_keys( $inviteArrayByID ) );
|
|
|
|
if ( count( $blockedInvitedUsers ) )
|
|
{
|
|
$this->exceptionData = $blockedInvitedUsers;
|
|
throw new Exception( "INVITE_USERS_BLOCKED" );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Check to ensure all invite users can use the PM system
|
|
//-----------------------------------------
|
|
|
|
foreach( $inviteArrayByID as $id => $_member )
|
|
{
|
|
$_member = $this->_setMaxMessages( $_member );
|
|
|
|
if ( $_member['g_use_pm'] != 1 OR $_member['members_disable_pm'] )
|
|
{
|
|
$cannotUsePM[ $id ] = $_member['members_display_name'];
|
|
}
|
|
|
|
if ( $this->withinPMQuota( $_member ) !== TRUE )
|
|
{
|
|
$cannotUsePM[ $id ] = $_member['members_display_name'];
|
|
}
|
|
|
|
if ( count( $cannotUsePM ) )
|
|
{
|
|
if ( $this->forceMessageToSend !== TRUE )
|
|
{
|
|
$this->exceptionData = $cannotUsePM;
|
|
throw new Exception( "NOT_ALL_INVITE_USERS_CAN_PM" );
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$finalArray[ $id ] = $_member;
|
|
}
|
|
|
|
|
|
return $finalArray;
|
|
}
|
|
|
|
/**
|
|
* Returns number of messages based on folders not a SQL search
|
|
*
|
|
* @param string ID of folder to get count from
|
|
* @param string Folder data line
|
|
* @return int Count
|
|
*/
|
|
public function getFolderTopicCount( $folderID, $folderData )
|
|
{
|
|
$folderArray = $this->explodeFolderData( $folderData );
|
|
|
|
return intval( $folderArray[ $folderID ]['count'] );
|
|
}
|
|
|
|
/**
|
|
* Rebuild directory count
|
|
*
|
|
* @param int Member ID
|
|
* @param string Folder ID to rebuild
|
|
* @param int Count of messages
|
|
* @param boolean Flag; do not save to DB [True is default]
|
|
* @param array Array of extra data for passing to IPSMember::save()
|
|
* @return string Rebuilt 'vdir' string
|
|
*/
|
|
public function rebuildFolderCount( $memberID, $folderAndCount=array(), $save=TRUE, $extraData=array() )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$rebuild = array();
|
|
$dirFolders = '';
|
|
|
|
//-----------------------------------------
|
|
// Got any current directories?
|
|
//-----------------------------------------
|
|
|
|
if ( $memberID == $this->memberData['member_id'] )
|
|
{
|
|
if ( $this->memberData['pconversation_filters'] )
|
|
{
|
|
$dirFolders = $this->memberData['pconversation_filters'];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$_member = IPSMember::load( $memberID, 'extendedProfile' );
|
|
$dirFolders = $_member['pconversation_filters'];
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Parse folder data
|
|
//-----------------------------------------
|
|
|
|
$rebuild = $this->explodeFolderData( $dirFolders );
|
|
|
|
//-----------------------------------------
|
|
// Sort out new count
|
|
//-----------------------------------------
|
|
|
|
foreach( $rebuild as $id => $data )
|
|
{
|
|
if ( isset($folderAndCount[ $id ]) )
|
|
{
|
|
$_count = $folderAndCount[ $id ];
|
|
|
|
if ( strstr( $_count, 'plus:' ) )
|
|
{
|
|
$newCount = $rebuild[ $data['id'] ]['count'] + intval( str_replace( 'plus:', '', $_count ) );
|
|
}
|
|
else if ( strstr( $_count, 'minus:' ) )
|
|
{
|
|
$newCount = $rebuild[ $data['id'] ]['count'] - intval( str_replace( 'minus:', '', $_count ) );
|
|
}
|
|
else
|
|
{
|
|
$newCount = $rebuild[ $data['id'] ]['count'] = intval( $_count );
|
|
}
|
|
|
|
$rebuild[ $data['id'] ]['count'] = ( $newCount < 1 ) ? 0 : $newCount;
|
|
}
|
|
}
|
|
|
|
$finalString = $this->implodeFolderData( $rebuild );
|
|
|
|
if ( $save === TRUE )
|
|
{
|
|
$extraData['extendedProfile']['pconversation_filters'] = $finalString;
|
|
|
|
IPSMember::save( $memberID, $extraData );
|
|
}
|
|
|
|
/* Update 'us' too.. */
|
|
if ( $memberID == $this->memberData['member_id'] )
|
|
{
|
|
$this->memberData['pconversation_filters'] = $finalString;
|
|
}
|
|
|
|
return $finalString;
|
|
}
|
|
|
|
/**
|
|
* Resets alert / count flag
|
|
* @param mixed $memberID
|
|
*/
|
|
public function resetMembersAlertCounts( $memberID )
|
|
{
|
|
$memberData = ( is_numeric( $memberID ) ) ? IPSMember::load( $memberID, 'extendedProfile' ) : $memberID;
|
|
|
|
IPSMember::save( $memberData['member_id'], array( 'core' => array( 'msg_count_new' => 0 ) ) );
|
|
IPSMember::setToMemberCache( $memberData, array( 'msgAlertReset' => IPS_UNIX_TIME_NOW ) );
|
|
}
|
|
|
|
/**
|
|
* Reset all folder counts
|
|
*
|
|
* @param int Member ID to reset
|
|
* @return boolean
|
|
*/
|
|
public function resetMembersFolderCounts( $memberID )
|
|
{
|
|
$memberData = IPSMember::load( $memberID, 'extendedProfile' );
|
|
|
|
/* Grab folders */
|
|
$folders = $this->explodeFolderData( $memberData['pconversation_filters'] );
|
|
|
|
/* Grab counts */
|
|
$counts = $this->getPersonalTopicsCount( $memberData['member_id'] );
|
|
|
|
/* Zero 'em out */
|
|
foreach( $folders as $folderID => $data )
|
|
{
|
|
$folders[ $folderID ]['count'] = 0;
|
|
}
|
|
|
|
if ( is_array( $counts ) )
|
|
{
|
|
foreach( $counts as $folderID => $count )
|
|
{
|
|
$folders[ $folderID ]['count'] = intval( $count );
|
|
}
|
|
}
|
|
|
|
/* Generate */
|
|
$dirs = $this->implodeFolderData( $folders );
|
|
|
|
/* Save */
|
|
IPSMember::save( $memberData['member_id'], array( 'core' => array( 'msg_count_reset' => 0 ),
|
|
'extendedProfile' => array( 'pconversation_filters' => $dirs ) ) );
|
|
|
|
/* Reset our counter */
|
|
if ( $memberID == $this->memberData['member_id'] )
|
|
{
|
|
$this->memberData['msg_count_reset'] = 0;
|
|
}
|
|
|
|
return $dirs;
|
|
}
|
|
|
|
/**
|
|
* Resets a user(s) new message count
|
|
*
|
|
* @param mixed Either INT member ID or ARRAY of member IDs
|
|
* @return boolean
|
|
*/
|
|
public function resetMembersNewTopicCount( $member )
|
|
{
|
|
//-----------------------------------------
|
|
// Load members...
|
|
//-----------------------------------------
|
|
|
|
if ( is_array( $member ) )
|
|
{
|
|
$members = IPSMember::load( $member, 'extendedProfile' );
|
|
}
|
|
else
|
|
{
|
|
$_member = IPSMember::load( $member, 'extendedProfile' );
|
|
$members = array( $_member['member_id'] => $_member );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Loop 'em
|
|
//-----------------------------------------
|
|
|
|
foreach( $members as $id => $data )
|
|
{
|
|
$count = intval( $this->getPersonalTopicsCount( $id, 'new' ) );
|
|
|
|
$lastReset = intval( IPSMember::getFromMemberCache( $data, 'msgAlertReset' ) );
|
|
$msgAlertCount = intval( $this->getPersonalTopicsCount( $id, 'new', $lastReset ) );
|
|
|
|
//-----------------------------------------
|
|
// Parse folder data
|
|
//-----------------------------------------
|
|
|
|
$rebuild = $this->explodeFolderData( $data['pconversation_filters'] );
|
|
$rebuild['new']['count'] = $count;
|
|
|
|
$msg_show_notification = ( $count ) ? $data['msg_show_notification'] : 0;
|
|
|
|
IPSMember::save( $id, array( 'extendedProfile' => array( 'pconversation_filters' => $this->implodeFolderData( $rebuild ) ),
|
|
'core' => array( 'msg_count_new' => $msgAlertCount,
|
|
'msg_show_notification' => $msg_show_notification ) ) );
|
|
|
|
IPSMember::setToMemberCache( $data, array( 'msgAlertReset' => IPS_UNIX_TIME_NOW ) );
|
|
|
|
/* Reset our counter */
|
|
if ( $id == $this->memberData['member_id'] )
|
|
{
|
|
$this->memberData['msg_count_new'] = $msgAlertCount;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Resets a members total message count
|
|
*
|
|
* @param int Member ID
|
|
* @return int Message count
|
|
*/
|
|
public function resetMembersTotalTopicCount( $memberID )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$memberID = intval( $memberID );
|
|
|
|
//-----------------------------------------
|
|
// Grab count
|
|
//-----------------------------------------
|
|
|
|
$total = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as msgTotal',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => "map_user_id=".$memberID." AND map_user_active=1 AND map_user_banned=0 AND map_is_system=0" ) );
|
|
|
|
$total['msgTotal'] = intval($total['msgTotal']);
|
|
|
|
IPSMember::save( $memberID, array( 'core' => array( 'msg_count_total' => $total['msgTotal'] ) ) );
|
|
|
|
return $total['msgTotal'];
|
|
}
|
|
|
|
/**
|
|
* Returns PM count on spec
|
|
*
|
|
* @param int Member ID
|
|
* @param string Folder ID (eg: inbox, sent, etc) [ Optional, if omitted, all msg box counts are returned ]
|
|
* @param int Timestamp to check from
|
|
* @return mixed If folder ID: Number of messages, otherwise an array of folderID => count
|
|
*/
|
|
public function getPersonalTopicsCount( $memberID, $folderID='', $time=null )
|
|
{
|
|
$return = array();
|
|
$where = '';
|
|
|
|
if ( is_numeric( $time ) )
|
|
{
|
|
$where = ( $folderID == 'drafts' ) ? ' AND mt_date > ' . $time : ' AND map_last_topic_reply > ' . $time;
|
|
}
|
|
|
|
if ( $memberID and $folderID )
|
|
{
|
|
/* New folder */
|
|
if ( $folderID == 'new' )
|
|
{
|
|
$t = $this->DB->buildAndFetch( array ( 'select' => 'COUNT(*) as msg_total',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => "map_user_active=1 AND map_user_id=" . intval( $memberID ) . " AND map_has_unread=1" . $where ) );
|
|
|
|
return intval( $t['msg_total'] );
|
|
}
|
|
/* Drafts */
|
|
else if ( $folderID == 'drafts' )
|
|
{
|
|
$t = $this->DB->buildAndFetch( array ( 'select' => 'COUNT(*) as msg_total',
|
|
'from' => 'message_topics',
|
|
'where' => "mt_starter_id=" . intval( $memberID ) . " AND mt_is_draft=1 AND mt_is_deleted=0" . $where ) );
|
|
|
|
return intval( $t['msg_total'] );
|
|
}
|
|
/* All other folders */
|
|
else
|
|
{
|
|
$_folder = $this->DB->addSlashes( $folderID );
|
|
|
|
if ( $this->_folderFilter )
|
|
{
|
|
if ( $this->_folderFilter == 'in' )
|
|
{
|
|
$t = $this->DB->buildAndFetch( array ( 'select' => 'COUNT(*) as msg_total',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => "map_user_id=" . intval( $memberID ) . " AND map_user_active=1 AND map_folder_id='" . $_folder . "' AND map_is_starter=0" . $where ) );
|
|
|
|
return intval( $t['msg_total'] );
|
|
}
|
|
else if ( $this->_folderFilter == 'sent' )
|
|
{
|
|
$t = $this->DB->buildAndFetch( array ( 'select' => 'COUNT(*) as msg_total',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => "map_user_id=" . intval( $memberID ) . " AND map_user_active=1 AND map_folder_id='" . $_folder . "' AND map_is_starter=1" . $where ) );
|
|
|
|
return intval( $t['msg_total'] );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$t = $this->DB->buildAndFetch( array ( 'select' => 'COUNT(*) as msg_total',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => "map_user_id=" . intval( $memberID ) . " AND map_user_active=1 AND map_folder_id='" . $_folder . "'" . $where ) );
|
|
|
|
return intval( $t['msg_total'] );
|
|
}
|
|
}
|
|
}
|
|
else if ( $memberID )
|
|
{
|
|
$this->DB->build( array( 'select' => 'COUNT(*) as msg_total, map_folder_id',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => "map_is_system=0 AND map_user_active=1 AND map_user_id=" . intval( $memberID ) . $where,
|
|
'group' => 'map_folder_id' ) );
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
$return[ $row['map_folder_id'] ] = $row['msg_total'];
|
|
}
|
|
|
|
$return['drafts'] = $this->getPersonalTopicsCount( $memberID, 'drafts' );
|
|
$return['new'] = $this->getPersonalTopicsCount( $memberID, 'new' );
|
|
|
|
return $return;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns PM data based on spec
|
|
*
|
|
* @param int Member ID
|
|
* @param string Folder ID (eg: inbox, sent, etc)
|
|
* @param array Array of data ( array[ 'sort' => '', offsetStart' => '', 'offsetEnd' => '' )
|
|
* @return array Array of PMs indexed by PM ID
|
|
*/
|
|
public function getPersonalTopicsList( $memberID, $folderID, $searchAndSort )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$sortKey = '';
|
|
$where = '';
|
|
$memberID = intval( $memberID );
|
|
$_memberIDs = array();
|
|
$folderID = IPSText::alphanumericalClean( $folderID, '-_' );
|
|
$oStart = intval( $searchAndSort['offsetStart'] );
|
|
$oEnd = intval( $searchAndSort['offsetEnd'] );
|
|
$messages = array();
|
|
|
|
//-----------------------------------------
|
|
// Figure out sort key
|
|
//-----------------------------------------
|
|
|
|
switch ( $searchAndSort['sort'] )
|
|
{
|
|
case 'rdate':
|
|
$sortKey = 'mm.map_last_topic_reply ASC';
|
|
break;
|
|
case 'title':
|
|
$sortKey = 'mt.mt_title ASC';
|
|
break;
|
|
case 'nameTo':
|
|
$sortKey = 'mem.members_display_name ASC';
|
|
break;
|
|
default:
|
|
$sortKey = 'mm.map_last_topic_reply DESC';
|
|
break;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Figure out where clause (no, not santa)
|
|
//-----------------------------------------
|
|
|
|
switch( $folderID )
|
|
{
|
|
default:
|
|
if ( $this->_folderFilter )
|
|
{
|
|
if ( $this->_folderFilter == 'in' )
|
|
{
|
|
$where = " AND mm.map_user_active=1 AND ( mm.map_folder_id='{$folderID}' AND mm.map_is_starter=0 )";
|
|
}
|
|
else if ( $this->_folderFilter == 'sent' )
|
|
{
|
|
$where = " AND mm.map_user_active=1 AND ( mm.map_folder_id='{$folderID}' AND mm.map_is_starter=1)";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$where = " AND mm.map_user_active=1 AND mm.map_folder_id='{$folderID}'";
|
|
}
|
|
break;
|
|
case 'drafts':
|
|
$where = " AND mm.map_user_active=1 AND mt.mt_is_draft=1";
|
|
break;
|
|
case 'new':
|
|
$where = ' AND mm.map_user_active=1 AND mm.map_has_unread=1';
|
|
break;
|
|
}
|
|
|
|
if ( ! $memberID or ! $folderID )
|
|
{
|
|
return $messages;
|
|
}
|
|
else
|
|
{
|
|
$this->DB->build( array( 'select' => 'mm.*',
|
|
'from' => array( 'message_topic_user_map' => 'mm' ),
|
|
'where' => "mm.map_user_id=" . $memberID . $where,
|
|
'order' => $sortKey,
|
|
'limit' => array( $oStart, $oEnd ),
|
|
'add_join' => array(
|
|
array( 'select' => 'mt.*',
|
|
'from' => array( 'message_topics' => 'mt' ),
|
|
'where' => 'mm.map_topic_id=mt.mt_id',
|
|
'type' => 'left'
|
|
),
|
|
array( 'select' => 'msg.*',
|
|
'from' => array( 'message_posts' => 'msg' ),
|
|
'where' => 'msg.msg_id=mt.mt_last_msg_id',
|
|
'type' => 'left'
|
|
),
|
|
array( 'select' => 'mem.members_display_name',
|
|
'from' => array( 'members' => 'mem' ),
|
|
'where' => 'mt.mt_to_member_id=mem.member_id',
|
|
'type' => 'left' ) ) ) );
|
|
$this->DB->execute();
|
|
|
|
//-----------------------------------------
|
|
// Get the messages
|
|
//-----------------------------------------
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
$_toID = intval( $row['mt_to_member_id'] );
|
|
$_startID = intval( $row['mt_starter_id'] );
|
|
$_lastID = intval( $row['msg_author_id'] );
|
|
|
|
/* Add member IDs */
|
|
$_memberIDs[ $_toID ] = $_toID;
|
|
$_memberIDs[ $_startID ] = $_startID;
|
|
$_memberIDs[ $_lastID ] = $_lastID;
|
|
|
|
/* Invited users */
|
|
if ( $row['mt_invited_members'] )
|
|
{
|
|
$row['_invitedMembers'] = unserialize( $row['mt_invited_members'] );
|
|
|
|
if ( is_array( $row['_invitedMembers'] ) AND count( $row['_invitedMembers'] ) )
|
|
{
|
|
foreach ( $row['_invitedMembers'] as $_mid )
|
|
{
|
|
$_memberIDs[ $_mid ] = $_mid;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Pagination */
|
|
if ( ( ($row['mt_replies'] + 1 ) % $this->messagesPerPage ) == 0 )
|
|
{
|
|
$pages = ($row['mt_replies'] + 1) / $this->messagesPerPage;
|
|
}
|
|
else
|
|
{
|
|
$number = ( ($row['mt_replies'] + 1) / $this->messagesPerPage );
|
|
$pages = ceil( $number);
|
|
}
|
|
|
|
if ( $pages > 1 )
|
|
{
|
|
for ( $i = 0 ; $i < $pages ; ++$i )
|
|
{
|
|
$real_no = $i * $this->messagesPerPage;
|
|
$page_no = $i + 1;
|
|
|
|
if ( $page_no == 4 and $pages > 4 )
|
|
{
|
|
$row['pages'][] = array( 'last' => 1,
|
|
'st' => ($pages - 1) * $this->messagesPerPage,
|
|
'page' => $pages );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
$row['pages'][] = array( 'last' => 0,
|
|
'st' => $real_no,
|
|
'page' => $page_no );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The rest */
|
|
$row['_folderName'] = $this->_dirData[ $row['map_folder_id'] ]['real'];
|
|
$row['_otherInviteeCount'] = intval( $row['mt_to_count'] - 1 );
|
|
$messages[ $row['mt_id'] ] = $row;
|
|
}
|
|
|
|
$members = array();
|
|
|
|
/* Got any members? */
|
|
if ( count( $_memberIDs ) )
|
|
{
|
|
$members = IPSMember::load( $_memberIDs, 'all' );
|
|
}
|
|
|
|
/* Let's sort out the ignore & photos at once for everyone */
|
|
if( count($members) )
|
|
{
|
|
foreach( $members as $_mid => $_mdata )
|
|
{
|
|
$_mdata['_canBeBlocked'] = IPSMember::isIgnorable( $_mdata['member_group_id'], $_mdata['mgroup_others'], 'pm' );
|
|
|
|
$members[ $_mid ] = IPSMember::buildProfilePhoto( $_mdata );
|
|
}
|
|
}
|
|
|
|
$members[ 0 ] = IPSMember::buildProfilePhoto( array( 'members_display_name' => $this->lang->words['deleted_user'] ) );
|
|
|
|
/* Now merge (in turn!) */
|
|
foreach( $messages as $id => $row )
|
|
{
|
|
/* From */
|
|
$messages[ $id ]['_starterMemberData'] = $members[ $row['mt_starter_id'] ];
|
|
|
|
/* To */
|
|
$messages[ $id ]['_toMemberData'] = $members[ $row['mt_to_member_id'] ];
|
|
|
|
/* Last msg author */
|
|
$messages[ $id ]['_lastMsgAuthor'] = $members[ $row['msg_author_id'] ];
|
|
|
|
/* Invitees */
|
|
if ( is_array( $row['_invitedMembers'] ) AND count( $row['_invitedMembers'] ) )
|
|
{
|
|
foreach ( $row['_invitedMembers'] as $_mid )
|
|
{
|
|
$messages[ $id ]['_invitedMemberData'][ $_mid ] = $members[ $_mid ];
|
|
$messages[ $id ]['_invitedMemberNames'][] = $members[ $_mid ]['members_display_name'];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$row['_invitedMembers'] = array();
|
|
$messages[ $id ]['_invitedMemberData'] = array();
|
|
$messages[ $id ]['_invitedMemberNames'] = array();
|
|
}
|
|
}
|
|
}
|
|
|
|
return $messages;
|
|
}
|
|
|
|
/**
|
|
* Returns a complete topic
|
|
*
|
|
* @param int Member ID
|
|
* @param string Folder ID (eg: inbox, sent, etc)
|
|
* @param array Array of data ( array[ sort => '', offsetStart' => '', 'offsetEnd' => '' )
|
|
* @return array Array of PMs indexed by PM ID
|
|
*
|
|
* <code>
|
|
* Exception Codes
|
|
* NO_READ_PERMISSION You do not have permission to read the topic
|
|
* YOU_ARE_BANNED You have been banned
|
|
* </code>
|
|
*/
|
|
public function fetchConversation( $topicID, $readingMemberID, $filters=array() )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$readingMemberID = intval( $readingMemberID );
|
|
$topicID = intval( $topicID );
|
|
$oStart = intval( $filters['offsetStart'] );
|
|
$oEnd = intval( $filters['offsetEnd'] );
|
|
$replyData = array();
|
|
$topicData = array();
|
|
$remapData = array();
|
|
$memberData = array();
|
|
$missingMembers = array();
|
|
$whereExtra = '';
|
|
|
|
//-----------------------------------------
|
|
// Figure out sort key
|
|
//-----------------------------------------
|
|
|
|
switch ( $filters['sort'] )
|
|
{
|
|
case 'rdate':
|
|
$sortKey = 'msg.msg_date DESC';
|
|
break;
|
|
default:
|
|
$sortKey = 'msg.msg_date ASC';
|
|
break;
|
|
}
|
|
|
|
if ( ! $topicID )
|
|
{
|
|
return array( 'topicData' => $topicData, 'replyData' => $replyData );
|
|
}
|
|
else
|
|
{
|
|
/* Get member data */
|
|
$memberData = $this->fetchTopicParticipants( $topicID, TRUE );
|
|
|
|
/* Get reading member's data */
|
|
$readingMemberData = $memberData[ $readingMemberID ];
|
|
|
|
/* Fetch topic data */
|
|
$topicData = $this->fetchTopicData( $topicID, FALSE );
|
|
|
|
/* Topic deleted? Grab topic starter details, as they won't be in the participant array */
|
|
if ( $topicData['mt_is_deleted'] AND ( $topicData['mt_starter_id'] > 0 ) )
|
|
{
|
|
$memberData[ $topicData['mt_starter_id'] ] = IPSMember::load( $topicData['mt_starter_id'], 'all' );
|
|
$memberData[ $topicData['mt_starter_id'] ]['_canBeBlocked'] = IPSMember::isIgnorable( $memberData[ $topicData['mt_starter_id'] ]['member_group_id'], $memberData[ $topicData['mt_starter_id'] ]['mgroup_others'], 'pm' );
|
|
$memberData[ $topicData['mt_starter_id'] ] = IPSMember::buildDisplayData( $memberData[ $topicData['mt_starter_id'] ], array( '__all__' => 1 ) );
|
|
$memberData[ $topicData['mt_starter_id'] ]['map_user_active'] = 1;
|
|
|
|
/* Set flag for topic participant starter */
|
|
$memberData[ $topicData['mt_starter_id'] ]['map_is_starter'] = 1;
|
|
|
|
foreach( $memberData as $id => $data )
|
|
{
|
|
$memberData[ $id ]['_topicDeleted'] = 1;
|
|
}
|
|
}
|
|
|
|
/* Can access this topic? */
|
|
if ( $this->canAccessTopic( $readingMemberID, $topicData, $memberData ) !== TRUE )
|
|
{
|
|
/* Banned? */
|
|
if ( $readingMemberData['map_user_banned'] )
|
|
{
|
|
throw new Exception( "YOU_ARE_BANNED" );
|
|
}
|
|
else
|
|
{
|
|
throw new Exception( "NO_READ_PERMISSION" );
|
|
}
|
|
}
|
|
|
|
/* Reply Data */
|
|
$this->DB->build( array( 'select' => 'msg.*',
|
|
'from' => array( 'message_posts' => 'msg' ),
|
|
'where' => "msg.msg_topic_id=" . $topicID . $whereExtra,
|
|
'order' => $sortKey,
|
|
'limit' => array( $oStart, $oEnd ),
|
|
'add_join' => array(
|
|
array( 'select' => 'iu.*',
|
|
'from' => array( 'ignored_users' => 'iu' ),
|
|
'where' => 'iu.ignore_owner_id=' . $readingMemberID . ' AND iu.ignore_ignore_id=msg.msg_author_id',
|
|
'type' => 'left' ),
|
|
array( 'select' => 'm.member_group_id, m.mgroup_others',
|
|
'from' => array( 'members' => 'm' ),
|
|
'where' => 'm.member_id=msg.msg_author_id',
|
|
'type' => 'left' ),
|
|
)
|
|
) );
|
|
$o = $this->DB->execute();
|
|
|
|
//-----------------------------------------
|
|
// Get the messages
|
|
//-----------------------------------------
|
|
|
|
while( $msg = $this->DB->fetch( $o ) )
|
|
{
|
|
$msg['_ip_address'] = "";
|
|
|
|
/* IP Address */
|
|
if ( $msg['msg_ip_address'] AND $readingMemberData['g_is_supmod'] == 1 )
|
|
{
|
|
$msg['_ip_address'] = $msg['msg_ip_address'];
|
|
}
|
|
|
|
/* Edit */
|
|
$msg['_canEdit'] = $this->_conversationCanEdit( $msg, $topicData, $readingMemberData );
|
|
|
|
/* Delete */
|
|
$msg['_canDelete'] = $this->_conversationCanDelete( $msg, $topicData, $readingMemberData );
|
|
|
|
/* Format Message */
|
|
$msg['msg_post'] = $this->_formatMessageForDisplay( $msg['msg_post'], $msg );
|
|
|
|
/* Member missing? */
|
|
if ( ! isset($memberData[ $msg['msg_author_id'] ]) )
|
|
{
|
|
if( !$msg['msg_author_id'] )
|
|
{
|
|
$memberData[0] = array();
|
|
}
|
|
else
|
|
{
|
|
$missingMembers[ $msg['msg_author_id'] ] = $msg['msg_author_id'];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ! empty( $memberData[ $msg['msg_author_id'] ]['signature'] ) )
|
|
{
|
|
if ( ! $this->memberData['view_sigs'] || ( $msg['msg_author_id'] && $this->memberData['member_id'] && ! empty( $this->member->ignored_users[ $msg['msg_author_id'] ]['ignore_signatures'] ) ) )
|
|
{
|
|
$memberData[ $msg['msg_author_id'] ]['signature'] = '';
|
|
}
|
|
}
|
|
}
|
|
|
|
$replyData[ $msg['msg_id'] ] = $msg;
|
|
}
|
|
}
|
|
|
|
/* Members who've deleted a closed conversation? */
|
|
if ( count( $missingMembers ) )
|
|
{
|
|
$_members = IPSMember::load( array_keys( $missingMembers ), 'all' );
|
|
|
|
foreach( $_members as $id => $data )
|
|
{
|
|
$data['_canBeBlocked'] = IPSMember::isIgnorable( $memberData[ $topicData['mt_starter_id'] ]['member_group_id'], $memberData[ $topicData['mt_starter_id'] ]['mgroup_others'], 'pm' );
|
|
$data['map_user_active'] = 0;
|
|
$memberData[ $data['member_id'] ] = IPSMember::buildDisplayData( $data, array( '__all__' => 1 ) );
|
|
}
|
|
}
|
|
|
|
/* Update reading member's read time */
|
|
$this->DB->update( 'message_topic_user_map', array( 'map_read_time' => time(), 'map_has_unread' => 0 ), 'map_user_id=' . intval($readingMemberData['member_id']) . ' AND map_topic_id=' . $topicID );
|
|
|
|
/* Reduce the number of 'new' messages */
|
|
$_newMsgs = intval( $this->getPersonalTopicsCount( $readingMemberID, 'new') );
|
|
|
|
if ( $memberData[ $readingMemberID ]['map_has_unread'] )
|
|
{
|
|
$lastReset = intval( IPSMember::getFromMemberCache( $memberData[ $readingMemberID ], 'msgAlertReset' ) );
|
|
$msgAlertCount = intval( $this->getPersonalTopicsCount( $readingMemberID, 'new', $lastReset ) );
|
|
|
|
$_pc = $this->rebuildFolderCount( $readingMemberID, array( 'new' => $_newMsgs ), TRUE );
|
|
IPSMember::save( $readingMemberID, array( 'core' => array( 'msg_count_new' => $msgAlertCount, 'msg_show_notification' => 0 ) ) );
|
|
|
|
/* is this us? */
|
|
if ( $readingMemberID == $this->memberData['member_id'] )
|
|
{
|
|
/* Reset folder data */
|
|
$this->_dirData = $this->explodeFolderData( $_pc );
|
|
|
|
/* Reset global new count */
|
|
$this->memberData['msg_count_new'] = $msgAlertCount;
|
|
}
|
|
}
|
|
|
|
/* Clean up topic title */
|
|
$topicData['mt_title'] = str_replace( '[attachmentid=', '[attachmentid=', $topicData['mt_title'] );
|
|
|
|
/* Flag externals as read */
|
|
$this->_flagAsReadForExternals( array( $topicID ) );
|
|
|
|
/* Ensure our read time is updated */
|
|
$memberData[ $readingMemberID ]['map_read_time'] = time();
|
|
|
|
/* Do we have a deleted user? */
|
|
if ( isset( $memberData[0] ) AND $memberData[0]['member_id'] == 0 )
|
|
{
|
|
$memberData[0] = IPSMember::buildDisplayData(IPSMember::setUpGuest( $this->lang->words['deleted_user'] ), array( '__all__' => 1 ) );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Attachments?
|
|
//-----------------------------------------
|
|
|
|
if ( $topicData['mt_hasattach'] )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT. Yes it is
|
|
//-----------------------------------------
|
|
|
|
$postHTML = array();
|
|
|
|
//-----------------------------------------
|
|
// Separate out post content
|
|
//-----------------------------------------
|
|
|
|
foreach( $replyData as $id => $post )
|
|
{
|
|
$postHTML[ $id ] = $post['msg_post'];
|
|
}
|
|
|
|
if ( ! is_object( $this->class_attach ) )
|
|
{
|
|
$classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'core' ) . '/sources/classes/attach/class_attach.php', 'class_attach' );
|
|
$this->class_attach = new $classToLoad( $this->registry );
|
|
}
|
|
|
|
$this->class_attach->type = 'msg';
|
|
$this->class_attach->init();
|
|
|
|
$attachHTML = $this->class_attach->renderAttachments( $postHTML );
|
|
|
|
/* Now parse back in the rendered posts */
|
|
foreach( $attachHTML as $id => $data )
|
|
{
|
|
/* Get rid of any lingering attachment tags */
|
|
if ( stristr( $data['html'], "[attachment=" ) )
|
|
{
|
|
$data['html'] = IPSText::stripAttachTag( $data['html'] );
|
|
}
|
|
|
|
$replyData[ $id ]['msg_post'] = $data['html'];
|
|
$replyData[ $id ]['attachmentHtml'] = $data['attachmentHtml'];
|
|
}
|
|
}
|
|
|
|
/* Check to make sure we're not the only one left with this topic */
|
|
$active = 0;
|
|
|
|
foreach( $memberData as $id => $data )
|
|
{
|
|
if ( $id !== $readingMemberID )
|
|
{
|
|
if ( $data['map_user_active'] )
|
|
{
|
|
$active++;
|
|
break; // 1 active is enough
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ! $active )
|
|
{
|
|
$topicData['_everyoneElseHasLeft'] = 1;
|
|
}
|
|
|
|
/* Return */
|
|
return array( 'topicData' => $topicData, 'replyData' => $replyData, 'memberData' => $memberData );
|
|
}
|
|
|
|
/**
|
|
* "Implode" folder string
|
|
*
|
|
* @param array Array indexed by 'id' => [ 'id' => string, 'real' => string, 'count' => int ]
|
|
* @return string Formed folder string
|
|
*/
|
|
public function implodeFolderData( $folderArray )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$return = array();
|
|
|
|
if ( ! is_array( $folderArray ) )
|
|
{
|
|
return serialize( $this->_fetchDefaultFolders() );
|
|
}
|
|
else
|
|
{
|
|
return serialize( $folderArray );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* "Explodes" folder string
|
|
*
|
|
* @param string Raw folder data
|
|
* @return array Array indexed by 'id' => [ 'id' => string, 'real' => string, 'count' => int ]
|
|
*/
|
|
public function explodeFolderData( $folderData )
|
|
{
|
|
//-----------------------------------------
|
|
// Set up default pconversation_filters
|
|
//-----------------------------------------
|
|
|
|
if ( ! $folderData )
|
|
{
|
|
$folderData = $this->_fetchDefaultFolders();
|
|
}
|
|
else
|
|
{
|
|
$folderData = unserialize( $folderData );
|
|
}
|
|
|
|
/* Fallback */
|
|
if ( !is_array( $folderData ) )
|
|
{
|
|
$folderData = $this->_fetchDefaultFolders();
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Process...
|
|
//-----------------------------------------
|
|
|
|
foreach( $folderData as $id => $data )
|
|
{
|
|
/* Language key exists? */
|
|
if ( isset( $this->lang->words[ 'msgFolder_' . $data['id'] ] ) )
|
|
{
|
|
$folderData[ $id ]['real'] = $this->lang->words[ 'msgFolder_' . $data['id'] ];
|
|
}
|
|
}
|
|
|
|
return $folderData;
|
|
}
|
|
|
|
/**
|
|
* Have we been blocked?
|
|
*
|
|
* @param array Person A: Array of member data (core + groups required) OR member ID
|
|
* @param array [Array of] member IDs to check 'person A' has been blocked by them. Array of member data (core + groups required) OR member ID OR array of IDs
|
|
* @return array
|
|
*/
|
|
public function blockedByUser( $fromMember, $toMember )
|
|
{
|
|
$fromMember = ( is_array( $fromMember ) ) ? $fromMember : IPSMember::load( intval( $fromMember ), 'groups,extendedProfile' );
|
|
$toMembers = array();
|
|
$blockedBy = array();
|
|
|
|
if ( is_array( $toMember ) AND ( $toMember['member_id'] != '' ) )
|
|
{
|
|
$toMembers = array( $toMember['member_id'] => $toMember );
|
|
}
|
|
else if ( is_array( $toMember ) AND count( $toMember ) )
|
|
{
|
|
$toMembers = IPSMember::load( $toMember, 'groups,extendedProfile' );
|
|
}
|
|
else
|
|
{
|
|
$toMembers = array( $toMember => IPSMember::load( intval( $toMember ), 'groups,extendedProfile' ) );
|
|
}
|
|
|
|
$justToIDs = array_keys( $toMembers );
|
|
|
|
//-----------------------------------------
|
|
// Can anyone block us?
|
|
//-----------------------------------------
|
|
|
|
if ( $fromMember['_canBeIgnored'] !== TRUE )
|
|
{
|
|
return $blockedBy;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Grab the data from the ignored table
|
|
//-----------------------------------------
|
|
$this->DB->build( array( 'select' => '*',
|
|
'from' => 'ignored_users',
|
|
'where' => 'ignore_messages=1 AND ignore_owner_id IN ( ' . implode( ',', $justToIDs ) . ' ) AND ignore_ignore_id=' . $fromMember['member_id'] ) );
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
if ( in_array( $row['ignore_owner_id'], $justToIDs ) )
|
|
{
|
|
$blockedBy[ $row['ignore_owner_id'] ] = $row['ignore_owner_id'];
|
|
}
|
|
}
|
|
|
|
return $blockedBy;
|
|
}
|
|
|
|
/**
|
|
* Can we use the PM system?
|
|
*
|
|
* @param array Array of member data (core + groups required) OR member ID
|
|
* @return boolean TRUE is OK
|
|
*/
|
|
public function canUsePMSystem( $toMember )
|
|
{
|
|
$toMember = ( is_array( $toMember ) ) ? $toMember : IPSMember::load( intval( $toMember ), 'groups,extendedProfile' );
|
|
|
|
/* Not using PM system? */
|
|
if ( $toMember['members_disable_pm'] )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( $toMember['mgroup_others'] && ! $toMember['g_use_pm'] )
|
|
{
|
|
$groups_id = explode( ',', $toMember['mgroup_others'] );
|
|
$cache = $this->caches['group_cache'];
|
|
|
|
if ( count( $groups_id ) )
|
|
{
|
|
foreach( $groups_id as $pid )
|
|
{
|
|
if ( ! $cache[ $pid ]['g_id'] )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( $cache[ $pid ]['g_use_pm'] )
|
|
{
|
|
$toMember['g_use_pm'] = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ( $toMember['g_use_pm'] != 1 ) ? FALSE : TRUE;
|
|
}
|
|
|
|
/**
|
|
* Get invite users
|
|
* Does this PM have any invite users attached? Mainly used to detect IPB 3.0.0 methods
|
|
* over previous methods
|
|
*
|
|
* @param string Raw data from DB (msg_cc_users)
|
|
* @return array Array of IDs
|
|
*/
|
|
public function getInvitedUsers( $msg_invite_users )
|
|
{
|
|
if ( ! $msg_invite_users )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
$_users = ( is_array( $msg_invite_users ) ) ? $msg_invite_users : unserialize( $msg_invite_users );
|
|
|
|
if ( ! count( $_users ) )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
if ( intval( $_users[0] ) == $_users[0] )
|
|
{
|
|
return $_users;
|
|
}
|
|
else
|
|
{
|
|
# Assume they're names, then...
|
|
$members = IPSMember::load( $_users, 'core', 'displayname' );
|
|
|
|
# Just return the IDs
|
|
return array_keys( $members );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Have we exceeded our PM quota?
|
|
*
|
|
* @param array Array of member data (core + groups required) OR member ID
|
|
* @return boolean TRUE is OK (within quota)
|
|
*/
|
|
public function withinPMQuota( $member )
|
|
{
|
|
$member = ( is_array( $member ) ) ? $member : IPSMember::load( intval( $member ), 'groups,extendedProfile' );
|
|
$member = $this->_setMaxMessages( $member );
|
|
|
|
if ( $member['g_max_messages'] > 0 AND ( $member['msg_count_total'] + 1 > $member['g_max_messages'] ) )
|
|
{
|
|
if ( $this->settings['override_inbox_full'] )
|
|
{
|
|
$override = array();
|
|
$override = explode( ",", $this->settings['override_inbox_full'] );
|
|
$do_override = 0;
|
|
|
|
$my_groups = array( $this->memberData['member_group_id'] );
|
|
|
|
if ( $this->memberData['mgroup_others'] )
|
|
{
|
|
$my_groups = array_merge( $my_groups, explode( ",", $this->memberData['mgroup_others'] ) );
|
|
}
|
|
|
|
foreach( $my_groups as $member_group )
|
|
{
|
|
if ( in_array( $member_group, $override ) )
|
|
{
|
|
$do_override = 1;
|
|
}
|
|
}
|
|
|
|
if ( $do_override == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the max PMs allowed based on primary and seconday groups
|
|
*
|
|
* @param array Array of member data
|
|
* @return array Member data
|
|
*/
|
|
protected function _setMaxMessages( $member )
|
|
{
|
|
$groups_id = explode( ',', $member['mgroup_others'] );
|
|
$groupCache = $this->caches['group_cache'];
|
|
|
|
if ( count( $groups_id ) )
|
|
{
|
|
foreach( $groups_id as $pid )
|
|
{
|
|
if ( empty($groupCache[ $pid ]['g_id']) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( $member['g_max_messages'] > 0 AND $groupCache[ $pid ]['g_max_messages'] > $member['g_max_messages'] )
|
|
{
|
|
$member['g_max_messages'] = $groupCache[ $pid ]['g_max_messages'];
|
|
}
|
|
else if ( $groupCache[ $pid ]['g_max_messages'] == 0 )
|
|
{
|
|
$member['g_max_messages'] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $member;
|
|
}
|
|
|
|
/**
|
|
* Builds the data for the messenger storage block
|
|
*
|
|
* @return array
|
|
*/
|
|
public function buildMessageTotals()
|
|
{
|
|
/* Get the number of messages we have in total. */
|
|
$total = $this->DB->buildAndFetch( array( 'select' => 'COUNT(*) as msg_total',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => "map_user_active=1 AND map_is_system=0 AND map_user_banned=0 AND map_user_id=" . $this->memberData['member_id'] ) );
|
|
|
|
$totals['msg_total'] = intval( $total['msg_total'] );
|
|
|
|
/* if we're not in myconvo with a filter */
|
|
if ( ! $this->_folderFilter )
|
|
{
|
|
/* Update the message count if needed */
|
|
if ( $totals['msg_total'] != $this->memberData['msg_count_total'] )
|
|
{
|
|
IPSMember::save( $this->memberData['member_id'], array( 'core' => array( 'msg_count_total' => $totals['msg_total'] ) ) );
|
|
}
|
|
}
|
|
|
|
/* Make sure we've not exceeded our alloted allowance. */
|
|
$info['full_messenger'] = "<br />";
|
|
$info['img_width'] = 1;
|
|
$info['vid'] = $this->_currentFolderID;
|
|
$info['full_percent'] = '';
|
|
$info['amount_info'] = sprintf( $this->lang->words['pmpc_info_string'], $total['msg_total'] ,$this->lang->words['pmpc_unlimited'] );
|
|
|
|
if ( $this->memberData['g_max_messages'] > 0 )
|
|
{
|
|
$totals['amount_info'] = sprintf( $this->lang->words['pmpc_info_string'], $total['msg_total'] ,$this->memberData['g_max_messages'] );
|
|
|
|
$totals['full_percent'] = $total['msg_total'] ? sprintf( "%.0f", ( ($total['msg_total'] / $this->memberData['g_max_messages']) * 100) ) : 0;
|
|
$totals['full_percent'] = ( $totals['full_percent'] > 100 ) ? 100 : $totals['full_percent'];
|
|
$totals['img_width'] = !empty( $info['full_percent'] ) ? intval($info['full_percent']) * 2.4 : 1;
|
|
|
|
if ($totals['img_width'] > 300)
|
|
{
|
|
$totals['img_width'] = 300;
|
|
}
|
|
|
|
if ($totals['msg_total'] >= $this->memberData['g_max_messages'])
|
|
{
|
|
$totals['full_messenger'] = "<span class='highlight'>".$this->lang->words['c_msg_full']."</span>";
|
|
}
|
|
else
|
|
{
|
|
$totals['full_messenger'] = str_replace( "<#PERCENT#>", $info['full_percent'], $this->lang->words['pmpc_full_string'] );
|
|
}
|
|
}
|
|
|
|
return $totals;
|
|
}
|
|
|
|
/**
|
|
* Test to see whether or not we are allowed in this PM topic
|
|
*
|
|
* @param int Member ID to test against
|
|
* @param mixed Topic ID or array of topic data
|
|
* @param array [ topic participants. If omitted, participants are loaded ]
|
|
* @param boolean Do not strip non-active users
|
|
* @return boolean
|
|
*/
|
|
public function canAccessTopic( $memberID, $topicData, $topicParticipants=NULL, $noStrip=FALSE )
|
|
{
|
|
$topicData = ( is_array( $topicData ) ) ? $topicData : $this->fetchTopicData( $topicData );
|
|
$topicParticipants = ( is_array( $topicParticipants ) ) ? $topicParticipants : $this->fetchTopicParticipants( $topicData['mt_id'] );
|
|
|
|
/* Is it deleted? Check this before stripped map_is_active=0 users */
|
|
if ( $topicData['mt_is_deleted'] AND isset($topicParticipants[ $memberID ]) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Is it a system PM? */
|
|
if ( $topicData['mt_is_system'] AND $topicData['mt_starter_id'] == $memberID )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( defined('FROM_REPORT_CENTER') AND FROM_REPORT_CENTER )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Now remove all 'non-active' participants */
|
|
$topicParticipants = ( $noStrip === FALSE ) ? $this->_stripNonActiveParticipants( $topicParticipants ) : $topicParticipants;
|
|
|
|
/* Are we in the participants list? */
|
|
if ( isset($topicParticipants[ $memberID ]) )
|
|
{
|
|
if ( $topicParticipants[ $memberID ]['map_user_banned'] )
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines whether the conversation can be replied to
|
|
*
|
|
* @param int Member ID to test against
|
|
* @param mixed Topic ID or array of topic data
|
|
* @param array [ topic participants. If omitted, participants are loaded ]
|
|
* @return boolean
|
|
*/
|
|
public function canReplyTopic( $memberID, $topicData, $topicParticipants=NULL )
|
|
{
|
|
$topicData = ( is_array( $topicData ) ) ? $topicData : $this->fetchTopicData( $topicData );
|
|
$topicParticipants = ( is_array( $topicParticipants ) ) ? $topicParticipants : $this->fetchTopicParticipants( $topicData['mt_id'] );
|
|
|
|
if ( $this->canAccessTopic( $memberID, $topicData, $topicParticipants ) !== TRUE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* Is it a system PM? */
|
|
if ( $topicData['mt_is_system'] )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* Is it a system PM? */
|
|
if ( $topicData['mt_is_deleted'] )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* Ok, then */
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Find the previous PID
|
|
*
|
|
* @param int Msg ID
|
|
* @return int Previous Msg ID
|
|
*/
|
|
public function fetchPreviousMsgID( $msgID )
|
|
{
|
|
$prevID = $this->DB->buildAndFetch( array( 'select' => 'MAX(msg_id) as max',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_id < ' . $msgID ) );
|
|
return intval( $prevID['max'] );
|
|
}
|
|
|
|
/**
|
|
* Fetch Message Data
|
|
*
|
|
* @param int Topic ID
|
|
* @param int Msg ID
|
|
* @param boolean Load starter member data with it
|
|
* @return array Message data
|
|
*/
|
|
public function fetchMessageData( $topicID, $msgID, $loadMember=FALSE )
|
|
{
|
|
$msgData = $this->DB->buildAndFetch( array( 'select' => '*',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_topic_id=' . intval( $topicID ) . ' AND msg_id=' . intval( $msgID ) ) );
|
|
|
|
if ( $loadMember AND $msgData['msg_author_id'] )
|
|
{
|
|
$memberData = IPSMember::load( $msgData['msg_author_id'], 'all' );
|
|
$memberData['_canBeBlocked'] = IPSMember::isIgnorable( $memberData['member_group_id'], $memberData['mgroup_others'], 'pm' );
|
|
$memberData = IPSMember::buildDisplayData( $memberData, array( '__all__' => 1 ) );
|
|
$msgData = array_merge( $msgData, $memberData );
|
|
}
|
|
|
|
return $msgData;
|
|
}
|
|
|
|
/**
|
|
* Fetch Message Data by ID
|
|
*
|
|
* @param int Msg ID
|
|
* @param boolean Load starter member data with it
|
|
* @return array Message data
|
|
*/
|
|
public function fetchMessageDataById( $msgID, $loadMember=FALSE )
|
|
{
|
|
$msgData = $this->DB->buildAndFetch( array( 'select' => '*',
|
|
'from' => 'message_posts',
|
|
'where' => 'msg_id=' . intval( $msgID ) ) );
|
|
|
|
if ( $loadMember AND $msgData['msg_author_id'] )
|
|
{
|
|
$memberData = IPSMember::load( $msgData['msg_author_id'], 'all' );
|
|
$memberData['_canBeBlocked'] = IPSMember::isIgnorable( $memberData['member_group_id'], $memberData['mgroup_others'], 'pm' );
|
|
$memberData = IPSMember::buildDisplayData( $memberData, array( '__all__' => 1 ) );
|
|
$msgData = array_merge( $msgData, $memberData );
|
|
}
|
|
|
|
return $msgData;
|
|
}
|
|
|
|
/**
|
|
* Fetch topic Data with first message information
|
|
*
|
|
* @param int Topic ID
|
|
* @param boolean Load starter member data with it
|
|
* @return array Topic + message data
|
|
*/
|
|
public function fetchTopicDataWithMessage( $topicID, $loadMember=FALSE )
|
|
{
|
|
$topicData = $this->DB->buildAndFetch( array( 'select' => 'mt.*',
|
|
'from' => array( 'message_topics' => 'mt' ),
|
|
'where' => 'mt.mt_id=' . intval( $topicID ),
|
|
'add_join' => array( array( 'select' => 'm.*',
|
|
'from' => array( 'message_posts' => 'm' ),
|
|
'where' => 'm.msg_id=mt.mt_first_msg_id',
|
|
'type' => 'inner' ) ) ) );
|
|
|
|
if ( $loadMember )
|
|
{
|
|
$memberData = IPSMember::load( $topicData['mt_starter_id'], 'all' );
|
|
$memberData['_canBeBlocked'] = IPSMember::isIgnorable( $memberData['member_group_id'], $memberData['mgroup_others'], 'pm' );
|
|
$memberData = IPSMember::buildDisplayData( $memberData, array( '__all__' => 1 ) );
|
|
$topicData = is_array($topicData) ? array_merge( $topicData, $memberData ) : $memberData;
|
|
}
|
|
|
|
return $topicData;
|
|
}
|
|
|
|
|
|
/**
|
|
* Fetch topic Data
|
|
*
|
|
* @param int Topic ID
|
|
* @param boolean Load starter member data with it
|
|
* @return array Topic data
|
|
*/
|
|
public function fetchTopicData( $topicID, $loadMember=FALSE )
|
|
{
|
|
$topicData = $this->DB->buildAndFetch( array( 'select' => '*',
|
|
'from' => 'message_topics',
|
|
'where' => 'mt_id=' . intval( $topicID ) ) );
|
|
|
|
if ( $loadMember )
|
|
{
|
|
$memberData = IPSMember::load( $topicData['mt_starter_id'], 'all' );
|
|
$memberData['_canBeBlocked'] = IPSMember::isIgnorable( $memberData['member_group_id'], $memberData['mgroup_others'], 'pm' );
|
|
$memberData = IPSMember::buildDisplayData( $memberData, array( '__all__' => 1 ) );
|
|
$topicData = array_merge( $topicData, $memberData );
|
|
}
|
|
|
|
return $topicData;
|
|
}
|
|
|
|
/**
|
|
* Fetch the topic participants
|
|
*
|
|
* @param int Topic ID
|
|
* @param boolean Load and parse member data (TRUE for yes, FALSE for no)
|
|
* @return array Array of member data indexed by member ID
|
|
*/
|
|
public function fetchTopicParticipants( $topicID, $parseThem=FALSE )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$memberData = array();
|
|
$remapData = array();
|
|
$cachedSigs = array();
|
|
|
|
//-----------------------------------------
|
|
// Grab 'em
|
|
//-----------------------------------------
|
|
|
|
$this->DB->build( array(
|
|
'select' => '*',
|
|
'from' => 'message_topic_user_map',
|
|
'where' => 'map_topic_id=' . intval( $topicID ),
|
|
) );
|
|
$this->DB->execute();
|
|
|
|
while( $row = $this->DB->fetch() )
|
|
{
|
|
$remapData[ $row['map_user_id'] ] = $row;
|
|
}
|
|
|
|
if( !count($remapData) )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/* Parse 'em? */
|
|
if ( $parseThem === TRUE )
|
|
{
|
|
/* Grab member data */
|
|
$memberData = IPSMember::load( array_keys( $remapData ), 'all' );
|
|
|
|
foreach( $memberData as $id => $data )
|
|
{
|
|
$data['cache_content'] = $remapData[ $id ]['cache_content'];
|
|
$data['_canBeBlocked'] = IPSMember::isIgnorable( $data['member_group_id'], $data['mgroup_others'], 'pm' );
|
|
$memberData[ $id ] = IPSMember::buildDisplayData( $data, array( '__all__' => 1 ) );
|
|
$memberData[ $id ] = array_merge( $memberData[ $id ], $remapData[ $id ] );
|
|
|
|
if ( $data['members_disable_pm'] )
|
|
{
|
|
$memberData[ $id ]['map_user_active'] = 0;
|
|
}
|
|
}
|
|
|
|
$remapData = $memberData;
|
|
}
|
|
|
|
return $remapData;
|
|
}
|
|
|
|
/**
|
|
* Strip away non-active participants
|
|
*
|
|
* @param array Array of current topic participants (as returned by fetchTopicParticipants)
|
|
* @return array
|
|
*/
|
|
protected function _stripNonActiveParticipants( $topicParticipants )
|
|
{
|
|
$_participants = array();
|
|
|
|
if ( ! is_array( $topicParticipants ) )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
foreach( $topicParticipants as $id => $data )
|
|
{
|
|
if ( $data['map_user_active'] and !$data['members_disable_pm'] )
|
|
{
|
|
$_participants[ $id ] = $data;
|
|
}
|
|
}
|
|
|
|
return $_participants;
|
|
}
|
|
|
|
/**
|
|
* Function to format the actual message (applies BBcode, etc)
|
|
*
|
|
* @param string Raw text
|
|
* @param array PM data
|
|
* @return string Processed text
|
|
*/
|
|
protected function _formatMessageForDisplay( $msgContent, $data=array() )
|
|
{
|
|
//-----------------------------------------
|
|
// Reset Classes
|
|
//-----------------------------------------
|
|
|
|
IPSText::resetTextClass('bbcode');
|
|
|
|
//-----------------------------------------
|
|
// Post process the editor
|
|
// Now we have safe HTML and bbcode
|
|
//-----------------------------------------
|
|
|
|
$this->settings['max_emos'] = 0 ;
|
|
|
|
IPSText::getTextClass('bbcode')->parse_smilies = 1;
|
|
IPSText::getTextClass('bbcode')->parse_nl2br = 1;
|
|
IPSText::getTextClass('bbcode')->parse_html = 0;//$this->caches['group_cache'][ $data['member_group_id'] ]['g_dohtml'];
|
|
IPSText::getTextClass('bbcode')->parse_bbcode = 1;
|
|
IPSText::getTextClass('bbcode')->parsing_section = 'pms';
|
|
IPSText::getTextClass( 'bbcode' )->parsing_mgroup = $data['member_group_id'];
|
|
IPSText::getTextClass( 'bbcode' )->parsing_mgroup_others = $data['mgroup_others'];
|
|
|
|
$msgContent = IPSText::getTextClass('bbcode')->preDisplayParse( $msgContent );
|
|
|
|
if ( IPSText::getTextClass('bbcode')->error != "" )
|
|
{
|
|
//throw new Exception( "BBCODE_" . IPSText::getTextClass('bbcode')->error );
|
|
}
|
|
|
|
return $msgContent;
|
|
}
|
|
|
|
/**
|
|
* Format Post: Converts BBCode, smilies, etc
|
|
*
|
|
* @param string Raw Post
|
|
* @return string Formatted Post
|
|
* @author MattMecham
|
|
*/
|
|
public function _formatMessageForSaving( $msgContent )
|
|
{
|
|
//-----------------------------------------
|
|
// Load editor
|
|
//-----------------------------------------
|
|
|
|
$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/editor/composite.php', 'classes_editor_composite' );
|
|
$_editor = new $classToLoad();
|
|
$_editor->setAllowHtml( false );
|
|
|
|
if ( IPS_IS_AJAX )
|
|
{
|
|
/* Was sent via std editor */
|
|
$_editor->setRteEnabled( false );
|
|
}
|
|
|
|
$msgContent = $_editor->process( $msgContent );
|
|
|
|
if ( IPS_IS_AJAX )
|
|
{
|
|
$msgContent = nl2br( $msgContent );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Parse post
|
|
//-----------------------------------------
|
|
|
|
IPSText::getTextClass('bbcode')->parse_smilies = 1;
|
|
IPSText::getTextClass('bbcode')->parse_nl2br = 1;
|
|
IPSText::getTextClass('bbcode')->parse_html = 0;//$this->memberData['g_dohtml'];
|
|
IPSText::getTextClass('bbcode')->parse_bbcode = 1;
|
|
IPSText::getTextClass('bbcode')->parsing_section = 'pms';
|
|
|
|
$msgContent = IPSText::getTextClass( 'bbcode' )->preDbParse( $msgContent );
|
|
|
|
if ( IPSText::getTextClass('bbcode')->error != "" )
|
|
{
|
|
throw new Exception( "BBCODE_" . IPSText::getTextClass('bbcode')->error );
|
|
}
|
|
|
|
return $msgContent;
|
|
}
|
|
|
|
/**
|
|
* Determines whether the message can be edited
|
|
*
|
|
* @param array Message data
|
|
* @param array Topic data
|
|
* @param array Reading member data
|
|
* @return bool
|
|
*/
|
|
protected function _conversationCanEdit( $msg, $topicData, $readingMemberData )
|
|
{
|
|
if ( $topicData['mt_is_deleted'] )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* Is it a system PM? */
|
|
if ( $topicData['mt_is_system'] )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( ( $msg['msg_author_id'] == $readingMemberData['member_id'] ) OR ( $readingMemberData['g_is_supmod'] == 1 ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines whether the message can be deleted
|
|
*
|
|
* @param array Message data
|
|
* @param array Topic data
|
|
* @param array Reading member data
|
|
* @return bool
|
|
*/
|
|
protected function _conversationCanDelete( $msg, $topicData, $readingMemberData )
|
|
{
|
|
if ( $topicData['mt_is_deleted'] )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( ( $msg['msg_author_id'] == $readingMemberData['member_id'] ) OR ( $readingMemberData['g_is_supmod'] == 1 ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flag members for a PC count reset
|
|
*
|
|
* @param array Array of MEMBER ids
|
|
* @return boolean
|
|
*/
|
|
protected function _flagForCountReset( $members )
|
|
{
|
|
if ( count( $members ) )
|
|
{
|
|
/* OK, so this is a bit naughty and should really go via IPSMember::save()
|
|
however, it would take a fair bit of rewriting to 'fix it' so that it could
|
|
save out with multiple IDs. So.... */
|
|
$this->DB->update( 'members', array( 'msg_count_reset' => 1 ), 'member_id IN (' . implode( ',', array_keys( $members ) ) . ')' );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Makes attachments permananent
|
|
*
|
|
* @param string Post Key
|
|
* @param int Msg ID
|
|
* @param int Topic ID
|
|
* @return int
|
|
*/
|
|
protected function _makeAttachmentsPermanent( $postKey, $msgID, $topicID )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$cnt = array( 'cnt' => 0 );
|
|
|
|
//-----------------------------------------
|
|
// Attachments: Re-affirm...
|
|
//-----------------------------------------
|
|
|
|
$classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'core' ) . '/sources/classes/attach/class_attach.php', 'class_attach' );
|
|
$class_attach = new $classToLoad( $this->registry );
|
|
$class_attach->type = 'msg';
|
|
$class_attach->attach_post_key = $postKey;
|
|
$class_attach->attach_rel_id = $msgID;
|
|
$class_attach->init();
|
|
|
|
$return = $class_attach->postProcessUpload( array( 'mt_id' => $topicID ) );
|
|
|
|
return intval( $return['count'] );
|
|
}
|
|
|
|
/**
|
|
* Flag external stuff
|
|
* @param array $data
|
|
*/
|
|
protected function _flagAsReadForExternals( array $data )
|
|
{
|
|
/* Notifications */
|
|
$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . '/sources/classes/member/notifications.php', 'notifications' );
|
|
$notifyLibrary = new $classToLoad( $this->registry );
|
|
$notifyLibrary->setMember( $this->memberData );
|
|
|
|
$notifyLibrary->deleteNotificationsAsReadByMetaData( array( 'meta_app' => 'members', 'meta_area' => 'pm', 'meta_id' => $data, 'notify_type_key' => 'new_private_message' ) );
|
|
}
|
|
|
|
/**
|
|
* Default folder for people won't don't have any
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function _fetchDefaultFolders()
|
|
{
|
|
return array( 'new' => array( 'id' => 'new',
|
|
'real' => $this->lang->words['msgFolder_new'],
|
|
'count' => 0,
|
|
'protected' => 1 ),
|
|
'myconvo' => array( 'id' => 'myconvo',
|
|
'real' => $this->lang->words['msgFolder_myconvo'],
|
|
'count' => 0,
|
|
'protected' => 1 ),
|
|
'drafts' => array( 'id' => 'drafts',
|
|
'real' => $this->lang->words['msgFolder_drafts'],
|
|
'count' => 0,
|
|
'protected' => 1 ) );
|
|
}
|
|
} |