Вход Регистрация
Файл: library/XenForo/Model/ThreadWatch.php
Строк: 410
<?php

/**
 * Model for thread watch records.
 *
 * @package XenForo_Thread
 */
class XenForo_Model_ThreadWatch extends XenForo_Model
{
    
/**
     * Gets a user's thread watch record for the specified thread ID.
     *
     * @param integer $userId
     * @param integer $threadId
     *
     * @return array|false
     */
    
public function getUserThreadWatchByThreadId($userId$threadId)
    {
        return 
$this->_getDb()->fetchRow('
            SELECT *
            FROM xf_thread_watch
            WHERE user_id = ?
                AND thread_id = ?
        '
, array($userId$threadId));
    }

    
/**
     * Get the thread watch records for a user, across many thread IDs.
     *
     * @param integer $userId
     * @param array $threadIds
     *
     * @return array Format: [thread_id] => thread watch info
     */
    
public function getUserThreadWatchByThreadIds($userId, array $threadIds)
    {
        if (!
$threadIds)
        {
            return array();
        }

        return 
$this->fetchAllKeyed('
            SELECT *
            FROM xf_thread_watch
            WHERE user_id = ?
                AND thread_id IN (' 
$this->_getDb()->quote($threadIds) . ')
        '
'thread_id'$userId);
    }

    
/**
     * Get a list of all users watching a thread. Includes permissions for the forum the thread is in.
     *
     * @param integer $threadId
     * @param integer $nodeId Forum the thread is in.
     *
     * @return array Format: [user_id] => info
     */
    
public function getUsersWatchingThread($threadId$nodeId)
    {
        
$autoReadDate XenForo_Application::$time - (XenForo_Application::get('options')->readMarkingDataLifetime 86400);

        return 
$this->fetchAllKeyed('
            SELECT user.*,
                user_option.*,
                user_profile.*,
                thread_watch.email_subscribe,
                permission.cache_value AS node_permission_cache,
                GREATEST(COALESCE(thread_read.thread_read_date, 0), COALESCE(forum_read.forum_read_date, 0), ' 
$autoReadDate ') AS thread_read_date
            FROM xf_thread_watch AS thread_watch
            INNER JOIN xf_user AS user ON
                (user.user_id = thread_watch.user_id AND user.user_state = '
valid' AND user.is_banned = 0)
            INNER JOIN xf_user_option AS user_option ON
                (user_option.user_id = user.user_id)
            INNER JOIN xf_user_profile AS user_profile ON
                (user_profile.user_id = user.user_id)
            LEFT JOIN xf_permission_cache_content AS permission
                ON (permission.permission_combination_id = user.permission_combination_id
                    AND permission.content_type = '
node'
                    AND permission.content_id = ?)
            LEFT JOIN xf_thread_read AS thread_read
                ON (thread_read.thread_id = thread_watch.thread_id AND thread_read.user_id = user.user_id)
            LEFT JOIN xf_forum_read AS forum_read
                ON (forum_read.node_id = ? AND forum_read.user_id = user.user_id)
            WHERE thread_watch.thread_id = ?
        '
'user_id', array($nodeId$nodeId$threadId));
    }

    protected static 
$_preventDoubleNotify = array();

    
/**
     * Send a notification to the users watching the thread.
     *
     * @param array $reply The reply that has been added
     * @param array|null $thread Info about the thread the reply is in; fetched if null
     * @param array $noAlerts List of user ids to NOT alert (but still send email)
     *
     * @return array Empty or keys: alerted: user ids alerted, emailed: user ids emailed
     */
    
public function sendNotificationToWatchUsersOnReply(array $reply, array $thread null, array $noAlerts = array())
    {
        if (
$reply['message_state'] != 'visible')
        {
            return array();
        }

        
$threadModel $this->_getThreadModel();

        
/* @var $userModel XenForo_Model_User */
        
$userModel $this->getModelFromCache('XenForo_Model_User');

        if (!
$thread)
        {
            
$thread $threadModel->getThreadById($reply['thread_id'], array(
                
'join' => XenForo_Model_Thread::FETCH_FORUM
            
));
        }
        if (!
$thread || $thread['discussion_state'] != 'visible')
        {
            return array();
        }

        
$autoReadDate XenForo_Application::$time - (XenForo_Application::get('options')->readMarkingDataLifetime 86400);

        
// get last 15 posts that could be relevant - need to go back in time for ignored reply handling
        
$latestPosts $this->getModelFromCache('XenForo_Model_Post')->getNewestPostsInThreadAfterDate(
            
$thread['thread_id'], $autoReadDate,
            array(
'limit' => 15)
        );
        if (!
$latestPosts)
        {
            return array();
        }

        
// the reply is likely the last post, so get the one before that and only
        // alert again if read since; note these posts are in newest first order
        
list($key) = each($latestPosts);
        unset(
$latestPosts[$key]);
        
$defaultPreviousPost reset($latestPosts);

        if (
XenForo_Application::get('options')->emailWatchedThreadIncludeMessage)
        {
            
$parseBbCode true;
            
$emailTemplate 'watched_thread_reply_messagetext';
        }
        else
        {
            
$parseBbCode false;
            
$emailTemplate 'watched_thread_reply';
        }

        
// fetch a full user record if we don't have one already
        
if (!isset($reply['avatar_width']) || !isset($reply['custom_title']))
        {
            
$replyUser $this->getModelFromCache('XenForo_Model_User')->getUserById($reply['user_id']);
            if (
$replyUser)
            {
                
$reply array_merge($replyUser$reply);
            }
            else
            {
                
$reply['avatar_width'] = 0;
                
$reply['custom_title'] = '';
            }
        }

        
$alerted = array();
        
$emailed = array();

        
$users $this->getUsersWatchingThread($thread['thread_id'], $thread['node_id']);
        foreach (
$users AS $user)
        {
            if (
$user['user_id'] == $reply['user_id'])
            {
                continue;
            }

            if (
$userModel->isUserIgnored($user$reply['user_id']))
            {
                continue;
            }

            if (!
$defaultPreviousPost || !$userModel->isUserIgnored($user$defaultPreviousPost['user_id']))
            {
                
$previousPost $defaultPreviousPost;
            }
            else
            {
                
// need to recalculate the last post that they would've seen
                
$previousPost false;
                foreach (
$latestPosts AS $latestPost)
                {
                    if (!
$userModel->isUserIgnored($user$latestPost['user_id']))
                    {
                        
// this is the most recent post they didn't ignore
                        
$previousPost $latestPost;
                        break;
                    }
                }
            }

            if (!
$previousPost || $previousPost['post_date'] < $autoReadDate)
            {
                
// always alert
            
}
            else if (
$previousPost['post_date'] > $user['thread_read_date'])
            {
                
// user hasn't read the thread since the last alert, don't send another one
                
continue;
            }

            
$permissions XenForo_Permission::unserializePermissions($user['node_permission_cache']);
            if (!
$threadModel->canViewThreadAndContainer($thread$thread$null$permissions$user))
            {
                continue;
            }

            if (isset(
self::$_preventDoubleNotify[$thread['thread_id']][$user['user_id']]))
            {
                continue;
            }
            
self::$_preventDoubleNotify[$thread['thread_id']][$user['user_id']] = true;

            if (
$user['email_subscribe'] && $user['email'] && $user['user_state'] == 'valid')
            {
                if (!isset(
$reply['messageText']) && $parseBbCode)
                {
                    
$bbCodeParserText XenForo_BbCode_Parser::create(XenForo_BbCode_Formatter_Base::create('Text'));
                    
$reply['messageText'] = new XenForo_BbCode_TextWrapper($reply['message'], $bbCodeParserText);

                    
$bbCodeParserHtml XenForo_BbCode_Parser::create(XenForo_BbCode_Formatter_Base::create('HtmlEmail'));
                    
$reply['messageHtml'] = new XenForo_BbCode_TextWrapper($reply['message'], $bbCodeParserHtml);
                }

                if (!isset(
$thread['titleCensored']))
                {
                    
$thread['titleCensored'] = XenForo_Helper_String::censorString($thread['title']);
                }

                
$user['email_confirm_key'] = $userModel->getUserEmailConfirmKey($user);

                
$mail XenForo_Mail::create($emailTemplate, array(
                    
'reply' => $reply,
                    
'thread' => $thread,
                    
'forum' => $thread,
                    
'receiver' => $user
                
), $user['language_id']);
                
$mail->enableAllLanguagePreCache();
                
$mail->queue($user['email'], $user['username']);

                
$emailed[] = $user['user_id'];
            }

            if (!
in_array($user['user_id'], $noAlerts))
            {
                
$alertType = ($reply['attach_count'] ? 'insert_attachment' 'insert');

                if (
XenForo_Model_Alert::userReceivesAlert($user'post'$alertType))
                {
                    
XenForo_Model_Alert::alert(
                        
$user['user_id'],
                        
$reply['user_id'],
                        
$reply['username'],
                        
'post',
                        
$reply['post_id'],
                        
$alertType
                    
);

                    
$alerted[] = $user['user_id'];
                }
            }
        }

        return array(
            
'emailed' => $emailed,
            
'alerted' => $alerted
        
);
    }

    
/**
     * Get the threads watched by a specific user.
     *
     * @param integer $userId
     * @param boolean $newOnly If true, only gets unread threads.
     * @param array $fetchOptions Thread fetch options (uses all valid for XenForo_Model_Thread).
     *
     * @return array Format: [thread_id] => info
     */
    
public function getThreadsWatchedByUser($userId$newOnly, array $fetchOptions = array())
    {
        
$fetchOptions['readUserId'] = $userId;
        
$fetchOptions['includeForumReadDate'] = true;

        
$joinOptions $this->_getThreadModel()->prepareThreadFetchOptions($fetchOptions);
        
$limitOptions $this->prepareLimitFetchOptions($fetchOptions);

        if (
$newOnly)
        {
            
$cutoff XenForo_Application::$time - (XenForo_Application::get('options')->readMarkingDataLifetime 86400);
            
$newOnlyClause '
                AND thread.last_post_date > ' 
$cutoff '
                AND thread.last_post_date > COALESCE(thread_read.thread_read_date, 0)
                AND thread.last_post_date > COALESCE(forum_read.forum_read_date, 0)
            '
;
        }
        else
        {
            
$newOnlyClause '';
        }

        return 
$this->fetchAllKeyed($this->limitQueryResults(
            
'
                SELECT thread.*,
                    thread_watch.email_subscribe
                    ' 
$joinOptions['selectFields'] . '
                FROM xf_thread_watch AS thread_watch
                INNER JOIN xf_thread AS thread ON
                    (thread.thread_id = thread_watch.thread_id)
                ' 
$joinOptions['joinTables'] . '
                WHERE thread_watch.user_id = ?
                    AND thread.discussion_state = '
visible'
                    ' 
$newOnlyClause '
                ORDER BY thread.last_post_date DESC
            '
$limitOptions['limit'], $limitOptions['offset']
        ), 
'thread_id'$userId);
    }

    
/**
     * Gets the total number of threads a user is watching.
     *
     * @param integer $userId
     *
     * @return integer
     */
    
public function countThreadsWatchedByUser($userId)
    {
        return 
$this->_getDb()->fetchOne('
            SELECT COUNT(*)
            FROM xf_thread_watch AS thread_watch
            INNER JOIN xf_thread AS thread ON
                (thread.thread_id = thread_watch.thread_id)
            WHERE thread_watch.user_id = ?
                AND thread.discussion_state = '
visible'
        '
$userId);
    }

    
/**
     * Take a list of threads (with the forum and permission info included in the thread)
     * and filters them to those that are viewable.
     *
     * @param array $threads List of threads, with forum info and permissions included
     * @param array|null $viewingUser
     *
     * @return array
     */
    
public function getViewableThreadsFromList(array $threads, array $viewingUser null)
    {
        
$this->standardizeViewingUserReference($viewingUser);

        
$threadModel $this->_getThreadModel();

        foreach (
$threads AS $key => $thread)
        {
            if (isset(
$thread['permissions']))
            {
                
$permissions $thread['permissions'];
            }
            else
            {
                
$permissions XenForo_Permission::unserializePermissions($thread['node_permission_cache']);
            }

            if (!
$threadModel->canViewThreadAndContainer($thread$thread$null$permissions$viewingUser))
            {
                unset(
$threads[$key]);
            }
        }

        return 
$threads;
    }

    
/**
     * Sets the thread watch state as requested. An empty state will delete any watch record.
     *
     * @param integer $userId
     * @param integer $threadId
     * @param string $state Values: watch_email, watch_no_email, (empty string)
     *
     * @return boolean
     */
    
public function setThreadWatchState($userId$threadId$state)
    {
        if (!
$userId)
        {
            return 
false;
        }

        
$threadWatch $this->getUserThreadWatchByThreadId($userId$threadId);

        switch (
$state)
        {
            case 
'watch_email':
            case 
'watch_no_email':
                
$dw XenForo_DataWriter::create('XenForo_DataWriter_ThreadWatch');
                if (
$threadWatch)
                {
                    
$dw->setExistingData($threadWatchtrue);
                }
                else
                {
                    
$dw->set('user_id'$userId);
                    
$dw->set('thread_id'$threadId);
                }
                
$dw->set('email_subscribe', ($state == 'watch_email' 0));
                
$dw->save();
                return 
true;

            case 
'':
                if (
$threadWatch)
                {
                    
$dw XenForo_DataWriter::create('XenForo_DataWriter_ThreadWatch');
                    
$dw->setExistingData($threadWatchtrue);
                    
$dw->delete();
                }
                return 
true;

            default:
                return 
false;
        }
    }

    public function 
setThreadWatchStateForAll($userId$state)
    {
        
$userId intval($userId);
        if (!
$userId)
        {
            return 
false;
        }

        
$db $this->_getDb();

        switch (
$state)
        {
            case 
'watch_email':
                return 
$db->update('xf_thread_watch',
                    array(
'email_subscribe' => 1),
                    
"user_id = " $db->quote($userId)
                );

            case 
'watch_no_email':
                return 
$db->update('xf_thread_watch',
                    array(
'email_subscribe' => 0),
                    
"user_id = " $db->quote($userId)
                );

            case 
'':
                return 
$db->delete('xf_thread_watch'"user_id = " $db->quote($userId));

            default:
                return 
false;
        }
    }

    
/**
     * Sets the thread watch state based on the user's default. This will never unwatch a thread.
     *
     * @param integer $userId
     * @param integer $threadId
     * @param string $state Values: watch_email, watch_no_email, (empty string)
     *
     * @return boolean
     */
    
public function setThreadWatchStateWithUserDefault($userId$threadId$state)
    {
        if (!
$userId)
        {
            return 
false;
        }

        
$threadWatch $this->getUserThreadWatchByThreadId($userId$threadId);
        if (
$threadWatch)
        {
            return 
true;
        }

        switch (
$state)
        {
            case 
'watch_email':
            case 
'watch_no_email':
                
$dw XenForo_DataWriter::create('XenForo_DataWriter_ThreadWatch');
                
$dw->set('user_id'$userId);
                
$dw->set('thread_id'$threadId);
                
$dw->set('email_subscribe', ($state == 'watch_email' 0));
                
$dw->save();
                return 
true;

            default:
                return 
false;
        }
    }

    
/**
     * Sets the thread watch state for the visitor from an array of input. Keys in input:
     *     * watch_thread_state: if true, uses watch_thread and watch_thread_email to set state as requested
     *  * watch_thread: if true, watches thread
     *  * watch_thread_email: if true (and watch_thread is true), watches thread with email; otherwise, watches thread without email
     *
     * @param integer $threadId
     * @param array $input
     *
     * @return boolean
     */
    
public function setVisitorThreadWatchStateFromInput($threadId, array $input)
    {
        
$visitor XenForo_Visitor::getInstance();

        if (!
$visitor['user_id'])
        {
            return 
false;
        }

        if (
$input['watch_thread_state'])
        {
            if (
$input['watch_thread'])
            {
                
$watchState = ($input['watch_thread_email'] ? 'watch_email' 'watch_no_email');
            }
            else
            {
                
$watchState '';
            }

            return 
$this->setThreadWatchState($visitor['user_id'], $threadId$watchState);
        }
        else
        {
            return 
$this->setThreadWatchStateWithUserDefault($visitor['user_id'], $threadId$visitor['default_watch_state']);
        }
    }

    
/**
     * Gets the thread watch state for the specified thread for the visiting user.
     *
     * @param integer|false $threadId Thread ID, or false if unknown
     * @param boolean $useDefaultIfNotWatching If true, uses visitor default if thread isn't watched
     *
     * @return string Values: watch_email, watch_no_email, (empty string)
     */
    
public function getThreadWatchStateForVisitor($threadId false$useDefaultIfNotWatching true)
    {
        
$visitor XenForo_Visitor::getInstance();
        if (!
$visitor['user_id'])
        {
            return 
'';
        }

        if (
$threadId)
        {
            
$threadWatch $this->getUserThreadWatchByThreadId($visitor['user_id'], $threadId);
        }
        else
        {
            
$threadWatch false;
        }

        if (
$threadWatch)
        {
            return (
$threadWatch['email_subscribe'] ? 'watch_email' 'watch_no_email');
        }
        else if (
$useDefaultIfNotWatching)
        {
            return 
$visitor['default_watch_state'];
        }
        else
        {
            return 
'';
        }
    }

    
/**
     * @return XenForo_Model_Thread
     */
    
protected function _getThreadModel()
    {
        return 
$this->getModelFromCache('XenForo_Model_Thread');
    }

    
/**
     * @return XenForo_Model_Alert
     */
    
protected function _getAlertModel()
    {
        return 
$this->getModelFromCache('XenForo_Model_Alert');
    }
}
Онлайн: 3
Реклама