Файл: library/XenForo/Model/ForumWatch.php
Строк: 366
<?php
class XenForo_Model_ForumWatch extends XenForo_Model
{
/**
* Gets a user's thread watch record for the specified forum ID.
*
* @param integer $userId
* @param integer $nodeId
*
* @return array|bool
*/
public function getUserForumWatchByForumId($userId, $nodeId)
{
return $this->_getDb()->fetchRow('
SELECT *
FROM xf_forum_watch
WHERE user_id = ?
AND node_id = ?
', array($userId, $nodeId));
}
/**
* Get the thread watch records for a user, across many node IDs.
*
* @param integer $userId
* @param array $nodeIds
*
* @return array Format: [node_id] => watch info
*/
public function getUserForumWatchByNodeIds($userId, array $nodeIds)
{
if (!$nodeIds)
{
return array();
}
return $this->fetchAllKeyed('
SELECT *
FROM xf_forum_watch
WHERE user_id = ?
AND node_id IN (' . $this->_getDb()->quote($nodeIds) . ')
', 'node_id', $userId);
}
/**
* @param integer $userId
*
* @return array
*/
public function getUserForumWatchByUser($userId)
{
return $this->fetchAllKeyed('
SELECT *
FROM xf_forum_watch
WHERE user_id = ?
', 'node_id', $userId);
}
/**
* Get a list of all users watching a forum. Includes permissions for the forum.
*
* @param integer $nodeId
* @param integer $threadId
* @param boolean $isReply
*
* @return array Format: [user_id] => info
*/
public function getUsersWatchingForum($nodeId, $threadId, $isReply = false)
{
$autoReadDate = XenForo_Application::$time - (XenForo_Application::get('options')->readMarkingDataLifetime * 86400);
if ($isReply)
{
$notificationLimit = "AND forum_watch.notify_on = 'message'";
}
else
{
$notificationLimit = "AND forum_watch.notify_on IN ('thread', 'message')";
}
return $this->fetchAllKeyed('
SELECT user.*,
user_option.*,
user_profile.*,
forum_watch.notify_on,
forum_watch.send_alert,
forum_watch.send_email,
permission.cache_value AS node_permission_cache,
GREATEST(COALESCE(thread_read.thread_read_date, 0), COALESCE(forum_read.forum_read_date, 0), ' . $autoReadDate . ') AS read_date
FROM xf_forum_watch AS forum_watch
INNER JOIN xf_user AS user ON
(user.user_id = forum_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 = forum_watch.node_id)
LEFT JOIN xf_forum_read AS forum_read
ON (forum_read.node_id = forum_watch.node_id AND forum_read.user_id = user.user_id)
LEFT JOIN xf_thread_read AS thread_read
ON (thread_read.thread_id = ? AND thread_read.user_id = user.user_id)
WHERE forum_watch.node_id = ?
' . $notificationLimit . '
AND (forum_watch.send_alert <> 0 OR forum_watch.send_email <> 0)
', 'user_id', array($threadId, $nodeId));
}
protected static $_preventDoubleNotify = array();
/**
* Send a notification to the users watching the thread.
*
* @param array $post The post being made
* @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)
* @param array $noEmail List of user ids to not send an email
*
* @return array Empty or keys: alerted: user ids alerted, emailed: user ids emailed
*/
public function sendNotificationToWatchUsersOnMessage(array $post, array $thread = null, array $noAlerts = array(), array $noEmail = array())
{
if ($post['message_state'] != 'visible')
{
return array();
}
$threadModel = $this->_getThreadModel();
/* @var $userModel XenForo_Model_User */
$userModel = $this->getModelFromCache('XenForo_Model_User');
if (!$thread)
{
$thread = $threadModel->getThreadById($post['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);
if ($post['position'] == 0)
{
$actionType = 'thread';
$latestPosts = array();
$defaultPreviousPost = false;
}
else
{
$actionType = 'message';
// 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_forum_' . $actionType . '_messagetext';
}
else
{
$parseBbCode = false;
$emailTemplate = 'watched_forum_' . $actionType;
}
// fetch a full user record if we don't have one already
if (!isset($post['avatar_width']) || !isset($post['custom_title']))
{
$postUser = $this->getModelFromCache('XenForo_Model_User')->getUserById($post['user_id']);
if ($postUser)
{
$post = array_merge($postUser, $post);
}
else
{
$post['avatar_width'] = 0;
$post['custom_title'] = '';
}
}
$alerted = array();
$emailed = array();
$users = $this->getUsersWatchingForum($thread['node_id'], $thread['thread_id'], $actionType == 'message');
foreach ($users AS $user)
{
if ($user['user_id'] == $post['user_id'])
{
continue;
}
if ($userModel->isUserIgnored($user, $post['user_id']))
{
continue;
}
if ($user['read_date'] >= $thread['last_post_date'])
{
// user has already read the entire thread
continue;
}
if ($actionType == 'message')
{
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['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['send_email'] && !in_array($user['user_id'], $noEmail)
&& $user['email'] && $user['user_state'] == 'valid')
{
if (!isset($post['messageText']) && $parseBbCode)
{
$bbCodeParserText = XenForo_BbCode_Parser::create(XenForo_BbCode_Formatter_Base::create('Text'));
$post['messageText'] = new XenForo_BbCode_TextWrapper($post['message'], $bbCodeParserText);
$bbCodeParserHtml = XenForo_BbCode_Parser::create(XenForo_BbCode_Formatter_Base::create('HtmlEmail'));
$post['messageHtml'] = new XenForo_BbCode_TextWrapper($post['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' => $post,
'thread' => $thread,
'forum' => $thread,
'receiver' => $user
), $user['language_id']);
$mail->enableAllLanguagePreCache();
$mail->queue($user['email'], $user['username']);
$emailed[] = $user['user_id'];
}
if ($user['send_alert'] && !in_array($user['user_id'], $noAlerts))
{
$alertType = ($post['attach_count'] ? 'insert_attachment' : 'insert');
XenForo_Model_Alert::alert(
$user['user_id'],
$post['user_id'],
$post['username'],
'post',
$post['post_id'],
$alertType
);
$alerted[] = $user['user_id'];
}
}
return array(
'emailed' => $emailed,
'alerted' => $alerted
);
}
/**
* Notify users of a thread being moved to a new forum. Attempt
* to prevent double notifications by not notifying people watching
* the source forum.
*
* @param array $firstPost
* @param integer $sourceForumId
*
* @return array
*/
public function sendNotificationToWatchUsersOnMove(array $firstPost, $sourceForumId)
{
$watchers = $this->_getDb()->fetchAll("
SELECT user_id, send_alert, send_email
FROM xf_forum_watch
WHERE node_id = ?
AND (send_alert = 1 OR send_email = 1)
", $sourceForumId);
$noAlert = array();
$noEmail = array();
foreach ($watchers AS $watcher)
{
if ($watcher['send_alert'])
{
$noAlert[] = $watcher['user_id'];
}
if ($watcher['send_email'])
{
$noEmail[] = $watcher['user_id'];
}
}
return $this->sendNotificationToWatchUsersOnMessage($firstPost, null, $noAlert, $noEmail);
}
/**
* Sets the forum watch state as requested. An empty state will delete any watch record.
*
* @param integer $userId
* @param integer $forumId
* @param string|null $notifyOn If "delete", watch record is removed
* @param boolean|null $sendAlert
* @param boolean|null $sendEmail
*
* @return boolean
*/
public function setForumWatchState($userId, $forumId, $notifyOn = null, $sendAlert = null, $sendEmail = null)
{
if (!$userId)
{
return false;
}
$forumWatch = $this->getUserForumWatchByForumId($userId, $forumId);
if ($notifyOn === 'delete')
{
if ($forumWatch)
{
$dw = XenForo_DataWriter::create('XenForo_DataWriter_ForumWatch');
$dw->setExistingData($forumWatch, true);
$dw->delete();
}
return true;
}
$dw = XenForo_DataWriter::create('XenForo_DataWriter_ForumWatch');
if ($forumWatch)
{
$dw->setExistingData($forumWatch, true);
}
else
{
$dw->set('user_id', $userId);
$dw->set('node_id', $forumId);
}
if ($notifyOn !== null)
{
$dw->set('notify_on', $notifyOn);
}
if ($sendAlert !== null)
{
$dw->set('send_alert', $sendAlert ? 1 : 0);
}
if ($sendEmail !== null)
{
$dw->set('send_email', $sendEmail ? 1 : 0);
}
$dw->save();
return true;
}
public function setForumWatchStateForAll($userId, $state)
{
$userId = intval($userId);
if (!$userId)
{
return false;
}
$db = $this->_getDb();
switch ($state)
{
case 'watch_email':
return $db->update('xf_forum_watch',
array('send_email' => 1),
"user_id = " . $db->quote($userId)
);
case 'watch_no_email':
return $db->update('xf_forum_watch',
array('send_email' => 0),
"user_id = " . $db->quote($userId)
);
case 'watch_alert':
return $db->update('xf_forum_watch',
array('send_alert' => 1),
"user_id = " . $db->quote($userId)
);
case 'watch_no_alert':
return $db->update('xf_forum_watch',
array('send_alert' => 0),
"user_id = " . $db->quote($userId)
);
case '':
return $db->delete('xf_forum_watch', "user_id = " . $db->quote($userId));
default:
return false;
}
}
/**
* @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');
}
}