| Server IP : 54.36.91.62 / Your IP : 216.73.217.112 Web Server : Apache System : Linux webm013.cluster127.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64 User : coopiak ( 151928) PHP Version : 8.3.23 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/coopiak/amisdesseniors-fr/bordeaux/libraries/kunena/src/Forum/Topic/ |
Upload File : |
<?php
/**
* Kunena Component
*
* @package Kunena.Framework
* @subpackage Forum.Topic
*
* @copyright Copyright (C) 2008 - @currentyear@ Kunena Team. All rights reserved.
* @license https://www.gnu.org/copyleft/gpl.html GNU/GPL
* @link https://www.kunena.org
**/
namespace Kunena\Forum\Libraries\Forum\Topic;
\defined('_JEXEC') or die();
use DateTime;
use DateTimeZone;
use Exception;
use InvalidArgumentException;
use Joomla\CMS\Application\SiteApplication;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\Exception\ExecutionFailureException;
use Kunena\Forum\Libraries\Access\KunenaAccess;
use Kunena\Forum\Libraries\Database\KunenaDatabaseObject;
use Kunena\Forum\Libraries\Date\KunenaDate;
use Kunena\Forum\Libraries\Error\KunenaError;
use Kunena\Forum\Libraries\Exception\KunenaExceptionAuthorise;
use Kunena\Forum\Libraries\Factory\KunenaFactory;
use Kunena\Forum\Libraries\Forum\Category\KunenaCategory;
use Kunena\Forum\Libraries\Forum\Category\KunenaCategoryHelper;
use Kunena\Forum\Libraries\Forum\Category\User\KunenaCategoryUserHelper;
use Kunena\Forum\Libraries\Forum\KunenaForum;
use Kunena\Forum\Libraries\Forum\Message\KunenaMessage;
use Kunena\Forum\Libraries\Forum\Message\KunenaMessageHelper;
use Kunena\Forum\Libraries\Forum\Message\Thankyou\KunenaMessageThankyouHelper;
use Kunena\Forum\Libraries\Forum\Topic\Poll\KunenaPoll;
use Kunena\Forum\Libraries\Forum\Topic\Poll\KunenaPollHelper;
use Kunena\Forum\Libraries\Forum\Topic\Rate\KunenaRateHelper;
use Kunena\Forum\Libraries\Forum\Topic\User\KunenaTopicUser;
use Kunena\Forum\Libraries\Forum\Topic\User\KunenaTopicUserHelper;
use Kunena\Forum\Libraries\Forum\Topic\User\Read\KunenaTopicUserReadHelper;
use Kunena\Forum\Libraries\Html\KunenaParser;
use Kunena\Forum\Libraries\Pagination\KunenaPagination;
use Kunena\Forum\Libraries\Route\KunenaRoute;
use Kunena\Forum\Libraries\User\KunenaUser;
use Kunena\Forum\Libraries\User\KunenaUserHelper;
use RuntimeException;
/**
* Class \Kunena\Forum\Libraries\Forum\Topic\Topic
*
* @property int $id
* @property int $categoryId
* @property string $subject
* @property int $icon_id
* @property int $locked
* @property int $hold
* @property int $ordering
* @property int $posts
* @property int $hits
* @property int $attachments
* @property int $poll_id
* @property int $moved_id
* @property int $first_post_id
* @property int $first_post_time
* @property int $first_post_userid
* @property string $first_post_message
* @property string $first_post_guest_name
* @property int $last_post_id
* @property int $last_post_time
* @property int $last_post_userid
* @property string $last_post_message
* @property string $last_post_guest_name
* @property string $params
* @property int $rating
* @property int $count
* @since Kunena 6.0
*/
class KunenaTopic extends KunenaDatabaseObject
{
/**
* @var array
* @since Kunena 6.0
*/
protected static $actions = [
'none' => [],
'read' => ['Read'],
'create' => ['NotExists', 'GuestWrite'],
'reply' => ['Read', 'NotHold', 'GuestWrite', 'NotMoved', 'Unlocked'],
'edit' => ['Read', 'NotMoved', 'Unlocked', 'Own'],
'move' => ['Read'],
'approve' => ['Read', 'NotMoved'],
'delete' => ['Read'],
'undelete' => ['Read'],
'permdelete' => ['Read', 'Permdelete'],
'favorite' => ['Read'],
'subscribe' => ['Read'],
'sticky' => ['Read'],
'lock' => ['Read'],
'rate' => ['Read', 'Unlocked'],
'poll.read' => ['Read', 'Poll'],
'poll.create' => ['Own'],
'poll.edit' => ['Read', 'NoVotes'],
'poll.delete' => ['Read', 'Own', 'Poll'],
'poll.vote' => ['Read', 'Poll', 'Vote'],
'post.read' => ['Read'],
'post.thankyou' => ['Read', 'NotMoved', 'Unlocked'],
'post.unthankyou' => ['Read', 'Unlocked'],
'post.reply' => ['Read', 'NotHold', 'GuestWrite', 'NotMoved', 'Unlocked'],
'post.edit' => ['Read', 'Unlocked'],
'post.move' => ['Read'],
'post.approve' => ['Read'],
'post.delete' => ['Read', 'Unlocked'],
'post.undelete' => ['Read'],
'post.permdelete' => ['Read', 'Permdelete'],
'post.attachment.read' => ['Read'],
'post.attachment.createimage' => ['Unlocked'],
'post.attachment.createfile' => ['Unlocked'],
'post.attachment.delete' => [],
'post.attachment.private' => [],
// TODO: In the future we might want to restrict this: array('Read','Unlocked'),
];
/**
* @var integer
* @since Kunena 6.0
*/
public $id = null;
/**
* @var integer
* @since Kunena 6.0
*/
public $unread = 0;
/**
* @var integer
* @since Kunena 6.0
*/
public $lastread = 0;
/**
* @var integer
* @since Kunena 6.0
*/
public $hold = 0;
/**
* @var integer
* @since Kunena 6.0
*/
public $posts = 0;
/**
* @var integer
* @since Kunena 6.0
*/
public $category_id = 0;
/**
* @var string
* @since Kunena 6.4
*/
public $subject;
/**
* @var string
* @since Kunena 6.4
*/
public $icon_id;
/**
* @var string
* @since Kunena 6.4
*/
public $label_id;
/**
* @var string
* @since Kunena 6.4
*/
public $locked;
/**
* @var string
* @since Kunena 6.4
*/
public $ordering;
/**
* @var string
* @since Kunena 6.4
*/
public $hits;
/**
* @var string
* @since Kunena 6.4
*/
public $attachments;
/**
* @var integer
* @since Kunena 6.4
*/
public $poll_id;
/**
* @var integer
* @since Kunena 6.4
*/
public $moved_id;
/**
* @var integer
* @since Kunena 6.4
*/
public $first_post_id;
/**
* @var string
* @since Kunena 6.4
*/
public $first_post_time;
/**
* @var integer
* @since Kunena 6.4
*/
public $first_post_userid;
/**
* @var string
* @since Kunena 6.4
*/
public $first_post_message;
/**
* @var string
* @since Kunena 6.4
*/
public $first_post_guest_name;
/**
* @var integer
* @since Kunena 6.4
*/
public $last_post_id;
/**
* @var string
* @since Kunena 6.4
*/
public $last_post_time;
/**
* @var integer
* @since Kunena 6.4
*/
public $last_post_userid;
/**
* @var string
* @since Kunena 6.4
*/
public $last_post_message;
/**
* @var string
* @since Kunena 6.4
*/
public $last_post_guest_name;
/**
* @var string
* @since Kunena 6.4
*/
public $rating;
/**
* @var string
* @since Kunena 6.4
*/
public $params;
/**
* @var string
* @since Kunena 6.4
*/
public $typeAlias;
/**
* @var integer
* @since Kunena 6.4
*/
public $categoryId;
/**
* @var string
* @since Kunena 6.4
*/
public $myposts;
/**
* @var integer
* @since Kunena 6.4
*/
public $my_last_post_id;
/**
* @var string
* @since Kunena 6.4
*/
public $favorite;
/**
* @var string
* @since Kunena 6.4
*/
public $title;
/**
* @var string
* @since Kunena 6.4
*/
public $titleName;
/**
* @var string
* @since Kunena 6.4
*/
public $titleCount;
/**
* @var string
* @since Kunena 6.4
*/
public $count;
/**
* @var string
* @since Kunena 6.4
*/
public $link;
/**
* @var string
* @since Kunena 6.4
*/
public $percent;
/**
* @var string
* @since Kunena 6.4
*/
public $avatar;
/**
* @var string
* @since Kunena 6.0
*/
protected $_table = 'KunenaTopics';
/**
* @var DatabaseDriver|void
* @since Kunena 6.0
*/
protected $_db = null;
/**
* @var array
* @since Kunena 6.0
*/
protected $_authcache = [];
/**
* @var array
* @since Kunena 6.0
*/
protected $_authccache = [];
/**
* @var array
* @since Kunena 6.0
*/
protected $_authfcache = [];
/**
* @var integer
* @since Kunena 6.0
*/
protected $_hold = 1;
/**
* @var integer
* @since Kunena 6.0
*/
protected $_posts = 0;
/**
* @var null
* @since Kunena 6.0
*/
protected $_pagination = null;
/**
* @param mixed $properties properties
*
* @throws Exception
* @since Kunena 6.0
*
* @internal
*/
public function __construct($properties = null)
{
if (!empty($this->id)) {
$this->_exists = true;
$this->_hold = $this->hold;
$this->_posts = $this->posts;
} else {
parent::__construct($properties);
}
$this->_db = Factory::getContainer()->get('DatabaseDriver');
}
/**
* Returns \Kunena\Forum\Libraries\Forum\Topic\Topic object.
*
* @param int $identifier The topic to load - Can be only an integer.
* @param bool $reset reset
*
* @return KunenaTopic
*
* @throws Exception
* @since Kunena 6.0
*/
public static function getInstance($identifier = null, $reset = false): KunenaTopic
{
return KunenaTopicHelper::get($identifier, $reset);
}
/**
* Subscribe / Unsubscribe user to this topic.
*
* @param int $value True for subscribe, false for unsubscribe.
* @param mixed $user user
*
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function subscribe(int $value, $user = null): bool
{
$usertopic = $this->getUserTopic($user);
$usertopic->subscribed = (int) $value;
try {
$usertopic->save();
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
return true;
}
/**
* @param mixed $user user
*
* @return KunenaTopicUser
*
* @throws Exception
* @since Kunena 6.0
*/
public function getUserTopic($user = null): KunenaTopicUser
{
return KunenaTopicUserHelper::get($this, $user);
}
/**
* Favorite / unfavorite user to this topic.
*
* @param bool $value True for favorite, false for unfavorite.
* @param mixed $user user
*
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function favorite($value = true, $user = null): bool
{
$usertopic = $this->getUserTopic($user);
$usertopic->favorite = (int) $value;
try {
$usertopic->save();
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
return true;
}
/**
* @param int $value values
*
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function sticky($value = 1): bool
{
$this->ordering = (int) $value;
return $this->save();
}
/**
* Method to save the \Kunena\Forum\Libraries\Forum\Topic\Topic object to the database.
*
* @param bool $cascade cascade
*
* @return boolean True on success.
*
* @throws Exception
* @since Kunena 6.0
*/
public function save($cascade = true): bool
{
$topicDelta = $this->delta();
$postDelta = $this->posts - $this->_posts;
if (!parent::save()) {
return false;
}
$this->_posts = $this->posts;
// Clear authentication cache
$this->_authfcache = $this->_authccache = $this->_authcache = [];
if ($cascade) {
$category = $this->getCategory();
try {
$category->update($this, $topicDelta, $postDelta);
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
return true;
}
/**
* @return integer
*
* @since Kunena 6.0
*/
protected function delta(): int
{
if (!$this->hold && $this->_hold) {
// Create or publish topic
return 1;
}
if ($this->hold && !$this->_hold) {
// Delete or unpublish topic
return -1;
}
return 0;
}
/**
* @param null|bool $exists exists
*
* @return boolean
*
* @since Kunena 6.0
*/
public function exists($exists = null): bool
{
if ($exists !== null) {
$this->_hold = $this->hold;
$this->_posts = $this->posts;
}
return parent::exists($exists);
}
/**
* @return KunenaCategory
*
* @throws Exception
* @since Kunena 6.0
*/
public function getCategory(): KunenaCategory
{
return KunenaCategoryHelper::get($this->category_id);
}
/**
* @return string
*
* @throws Exception
* @since Kunena 6.0
*/
public function getActions(): string
{
$txt = '';
if ($this->ordering) {
$txt = $this->getCategory()->class_sfx ? $txt . '' : $txt . '-stickymsg';
}
if ($this->hold == 1) {
$txt .= ' unapproved';
} else {
if ($this->hold) {
$txt .= ' deleted';
}
}
if ($this->moved_id > 0) {
$txt .= ' moved';
}
if ($this->locked) {
$txt .= ' locked';
}
return $txt;
}
/**
* @param int $value value
*
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function lock($value = 1): bool
{
$this->locked = (int) $value;
return $this->save();
}
/**
* @param mixed $user user
* @param bool|string $glue glue
*
* @return void
*
* @since Kunena 6.0
*/
public function getKeywords($user = null, $glue = false): void
{
}
/**
* @param int $value value
*
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function publish($value = KunenaForum::PUBLISHED): bool
{
if ($value < 0 || $value > 3) {
$value = 0;
}
$this->hold = (int) $value;
$query = $this->_db->createQuery();
$query->update($this->_db->quoteName('#__kunena_messages'))
->set($this->_db->quoteName('hold') . ' = ' . $this->_db->quote($this->hold))
->where($this->_db->quoteName('thread') . ' = ' . (int) $this->id . ' AND ' . $this->_db->quoteName('hold') . ' = ' . $this->_db->quote($this->_hold));
$this->_db->setQuery($query);
try {
$this->_db->execute();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
return false;
}
return $this->_db->getAffectedRows() ? $this->recount() : $this->save();
}
/**
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function recount(): bool
{
if (!$this->moved_id) {
// Recount total posts and attachments
$query = $this->_db->createQuery();
$query->select('COUNT(DISTINCT ' . $this->_db->quoteName('m.id') . ') AS ' . $this->_db->quoteName('posts') . ', COUNT(' . $this->_db->quoteName('a.id') . ') AS ' . $this->_db->quoteName('attachments'))
->from($this->_db->quoteName('#__kunena_messages', 'm'))
->leftJoin($this->_db->quoteName('#__kunena_attachments', 'a') . ' ON ' . $this->_db->quoteName('m.id') . ' = ' . $this->_db->quoteName('a.mesid'))
->where($this->_db->quoteName('m.hold') . ' = ' . $this->_db->quote($this->hold) . ' AND ' . $this->_db->quoteName('m.thread') . ' = ' . $this->_db->quote($this->id))
->group($this->_db->quoteName('m.thread'));
$this->_db->setQuery($query);
try {
$result = $this->_db->loadAssoc();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
return false;
}
if (!$result) {
$this->posts = 0;
// Double check if all posts have been removed from the database
$query = $this->_db->createQuery();
$query->select('COUNT(' . $this->_db->quoteName('m.id') . ') AS ' . $this->_db->quoteName('posts') . ', MIN(' . $this->_db->quoteName('m.hold') . ') AS ' . $this->_db->quoteName('hold'))
->from($this->_db->quoteName('#__kunena_messages', 'm'))
->where($this->_db->quoteName('m.thread') . ' = ' . $this->_db->quote($this->id))
->group($this->_db->quoteName('m.thread'));
$this->_db->setQuery($query);
try {
$result = $this->_db->loadAssoc();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
return false;
}
if ($result) {
// Information in the database was wrong, recount topic
$this->hold = $result['hold'];
$this->recount();
}
return true;
}
$this->bind($result);
}
return $this->update();
}
/**
* @param KunenaMessage $message message
* @param int $postdelta postdelta
*
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function update($message = null, $postdelta = 0): bool
{
// Update post count
$this->posts += $postdelta;
$exists = $message && $message->exists();
if (!$this->exists()) {
if (!$exists) {
throw new Exception(Text::_('COM_KUNENA_LIB_TOPIC_NOT_EXISTS'));
}
$this->id = $message->id;
}
if ($exists && $message->thread == $this->id && $message->hold == $this->hold) {
// If message belongs into this topic and has same state, we may need to update cache
$this->updatePostInfo($message->id, $message->time, $message->userid, $message->message, $message->name);
} elseif (!$this->moved_id) {
if (!isset($this->hold)) {
$this->hold = KunenaForum::TOPIC_DELETED;
}
// If message isn't visible anymore, check if we need to update cache
if (!$exists || $this->first_post_id == $message->id) {
// If message got deleted and was cached, we need to find new first post
$db = Factory::getContainer()->get('DatabaseDriver');
$query = $this->_db->createQuery();
$query->select('*')
->from($this->_db->quoteName('#__kunena_messages', 'm'))
->innerJoin($this->_db->quoteName('#__kunena_messages_text', 't') . ' ON ' . $this->_db->quoteName('t.mesid') . '=' . $this->_db->quoteName('m.id'))
->where($this->_db->quoteName('m.thread') . ' = ' . $db->quote($this->id) . ' AND ' . $this->_db->quoteName('m.hold') . ' = ' . $this->_db->quote($this->hold))
->order($this->_db->quoteName('m.time') . ' ASC, ' . $this->_db->quoteName('m.id') . ' ASC');
$query->setLimit(1);
$db->setQuery($query);
try {
$first = $db->loadObject();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
}
if ($first) {
$this->first_post_time = 0;
$this->updatePostInfo($first->id, $first->time, $first->userid, $first->message, $first->name);
} else {
$this->updatePostInfo(false);
}
}
if (!$exists || $this->last_post_id == $message->id) {
// If topic got deleted and was cached, we need to find new last post
$db = Factory::getContainer()->get('DatabaseDriver');
$query = $this->_db->createQuery();
$query->select('*')
->from($this->_db->quoteName('#__kunena_messages', 'm'))
->innerJoin($this->_db->quoteName('#__kunena_messages_text', 't') . ' ON ' . $this->_db->quoteName('t.mesid') . ' = ' . $this->_db->quoteName('m.id'))
->where($this->_db->quoteName('m.thread') . ' = ' . $db->quote($this->id) . ' AND ' . $this->_db->quoteName('m.hold') . ' = ' . $this->_db->quote($this->hold))
->order($this->_db->quoteName('m.time') . ' DESC, ' . $this->_db->quoteName('m.id') . ' DESC');
$query->setLimit(1);
$db->setQuery($query);
try {
$last = $db->loadObject();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
}
if ($last) {
$this->last_post_time = 0;
$this->updatePostInfo($last->id, $last->time, $last->userid, $last->message, $last->name);
} else {
$this->updatePostInfo(false);
}
}
}
if (!$this->first_post_id || !$this->last_post_id) {
// If topic has no visible posts, mark it deleted and recount
$this->hold = $exists ? $message->hold : KunenaForum::TOPIC_DELETED;
$this->recount();
}
if (!($message && $message->exists()) && !$this->posts) {
return $this->delete();
}
if (!$this->save()) {
return false;
}
if ($exists && $message->userid && abs($postdelta) <= 1) {
// Update user topic
$usertopic = $this->getUserTopic($message->userid);
try {
$usertopic->update($message, $postdelta);
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
// Update post count from user
$user = KunenaUserHelper::get($message->userid);
$user->posts += $postdelta;
try {
$user->save();
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
} else {
KunenaTopicUserHelper::recount($this->id);
// FIXME: optimize
KunenaUserHelper::recount();
}
return true;
}
/**
* @param int $id id
* @param int $time time
* @param int $userid userid
* @param string $message message
* @param string $name name
*
* @return void
*
* @since Kunena 6.0
*/
public function updatePostInfo($id, $time = 0, $userid = 0, $message = '', $name = ''): void
{
if ($id === false) {
$this->first_post_id = 0;
$this->first_post_time = 0;
$this->first_post_userid = 0;
$this->first_post_message = '';
$this->first_post_guest_name = '';
$this->last_post_id = 0;
$this->last_post_time = 0;
$this->last_post_userid = 0;
$this->last_post_message = '';
$this->last_post_guest_name = '';
return;
}
if (!$this->first_post_time || ($this->first_post_time > $time || ($this->first_post_time == $time && $this->first_post_id >= $id))) {
$this->first_post_id = $id;
$this->first_post_time = $time;
$this->first_post_userid = $userid;
$this->first_post_message = $message;
$this->first_post_guest_name = $name;
}
if ($this->last_post_time < $time || ($this->last_post_time == $time && $this->last_post_id <= $id)) {
$this->last_post_id = $id;
$this->last_post_time = $time;
$this->last_post_userid = $userid;
$this->last_post_message = $message;
$this->last_post_guest_name = $name;
}
}
/**
* Method to delete the \Kunena\Forum\Libraries\Forum\Topic\Topic object from the database.
*
* @param bool $recount recount
*
* @return boolean True on success.
*
* @throws Exception
* @since Kunena 6.0
*/
public function delete($recount = true): bool
{
if (!$this->exists()) {
return true;
}
if (!parent::delete()) {
return false;
}
// Clear authentication cache
$this->_authfcache = $this->_authccache = $this->_authcache = [];
// NOTE: shadow topic doesn't exist, DO NOT DELETE OR CHANGE ANY EXTERNAL INFORMATION
if ($this->moved_id == 0) {
$db = Factory::getContainer()->get('DatabaseDriver');
// Delete user topics
$queries[] = "DELETE FROM #__kunena_user_topics WHERE topic_id={$db->quote($this->id)}";
// Delete user read
$queries[] = "DELETE FROM #__kunena_user_read WHERE topic_id={$db->quote($this->id)}";
if ($this->poll_id) {
// Delete poll (users)
$queries[] = "DELETE FROM #__kunena_polls_users WHERE pollid={$db->quote($this->poll_id)}";
// Delete poll (options)
$queries[] = "DELETE FROM #__kunena_polls_options WHERE pollid={$db->quote($this->poll_id)}";
// Delete poll
$queries[] = "DELETE FROM #__kunena_polls WHERE id={$db->quote($this->poll_id)}";
}
// Delete thank yous
$queries[] = "DELETE t FROM #__kunena_thankyou AS t INNER JOIN #__kunena_messages AS m ON m.id=t.postid WHERE m.thread={$db->quote($this->id)}";
// Delete all messages
$queries[] = "DELETE m, t FROM #__kunena_messages AS m INNER JOIN #__kunena_messages_text AS t ON m.id=t.mesid WHERE m.thread={$db->quote($this->id)}";
// Delete rating
$queries[] = "DELETE FROM #__kunena_rate WHERE topic_id={$db->quote($this->id)}";
foreach ($queries as $query) {
$db->setQuery($query);
try {
$db->execute();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
return false;
}
}
// FIXME: add recount statistics
if ($recount) {
KunenaUserHelper::recount();
KunenaMessageThankyouHelper::recount();
}
}
return true;
}
/**
* Send email notifications from the first post in the topic.
*
* @param null|string $url url
* @param bool $approved
*
* @return void
*
* @throws Exception
* @since Kunena 6.0
*/
public function sendNotification($url = null, $approved = false): void
{
// Reload message just in case if it was published by bulk update.
KunenaMessageHelper::get($this->first_post_id, true)->sendNotification($url, $approved);
}
/**
* @return KunenaUser
*
* @throws Exception
* @since Kunena 6.0
*/
public function getAuthor(): KunenaUser
{
return KunenaUserHelper::getAuthor($this->first_post_userid, $this->first_post_guest_name);
}
/**
* @return integer
*
* @since Kunena 6.0
*/
public function getHits(): int
{
return $this->hits;
}
/**
* Increase hit counter for this topic.
*
* @return void
*
* @throws Exception
* @since Kunena 6.0
*/
public function hit(): void
{
$app = Factory::getApplication();
$lasthit = $app->getUserState('com_kunena.topic.lasthit');
if ($lasthit == $this->id) {
return;
}
// Update only hit - not entire object
$table = $this->getTable();
$table->id = $this->id;
if ($table->hit()) {
$this->hits++;
$app->setUserState('com_kunena.topic.lasthit', $this->id);
}
}
/**
* @param int $limitstart Null if all pages need to be active.
* @param int $limit limit
* @param int $display display
* @param string $prefix prefix
*
* @return \Kunena\Forum\Libraries\Pagination\KunenaPagination|null
*
* @since Kunena 6.0
* @throws \Exception
*/
public function getPagination($limitstart = 0, $limit = 6, $display = 4, $prefix = ''): ?KunenaPagination
{
if (!$this->_pagination) {
$this->_pagination = new KunenaPagination($this->posts, $limitstart, $limit, $prefix);
$this->_pagination
->setUri($this->getUri())
->setDisplayedPages($display);
if ($limitstart == null) {
$this->_pagination->pagesCurrent = 0;
}
}
return $this->_pagination;
}
/**
* @param mixed $category category
* @param KunenaMessage|string|null $action action
* @param int $itemid itemid
*
* @return \Joomla\CMS\Uri\Uri
*
* @throws \Exception
* @since Kunena 6.0
*/
public function getUri($category = null, $action = null, $Itemid = 0): Uri
{
$category = $category ? KunenaCategoryHelper::get($category) : $this->getCategory();
if ($Itemid == 0) {
$Itemid = KunenaRoute::getCategoryItemid($category);
}
if ($action instanceof KunenaMessage) {
$message = $action;
$action = 'post' . $message->id;
}
$uri = Uri::getInstance("index.php?option=com_kunena&view=topic&catid={$category->id}&id={$this->id}&action={$action}&Itemid={$Itemid}");
if ($uri->getVar('action') !== null) {
$uri->delVar('action');
$mesid = 0;
$limit = max(1, \intval(KunenaFactory::getConfig()->messagesPerPage));
if (isset($message)) {
$mesid = $message->id;
} elseif ((string) $action === (string) (int) $action) {
if ($action > 0) {
$uri->setVar('limitstart', $action * $limit);
}
} else {
switch ($action) {
case 'first':
$mesid = $this->first_post_id;
break;
case 'last':
$mesid = $this->last_post_id;
break;
case 'unread':
// Special case, improves caching
$uri->setVar('layout', 'unread');
// $mesid = $this->lastread ? $this->lastread : $this->last_post_id;
break;
}
}
if ($mesid) {
$uri->setFragment($mesid);
$limitstart = \intval($this->getPostLocation($mesid) / $limit) * $limit;
if ($limitstart) {
$uri->setVar('limitstart', $limitstart);
}
}
}
return $uri;
}
/**
* @param int $mesid mesid
* @param string|null $direction direction
* @param mixed $hold hold
*
* @return integer
*
* @throws Exception
* @since Kunena 6.0
*/
public function getPostLocation(int $mesid, $direction = null, $hold = null): int
{
if (\is_null($direction)) {
$direction = KunenaUserHelper::getMyself()->getMessageOrdering();
}
if (!isset($this->lastread)) {
$this->lastread = $this->last_post_id;
$this->unread = 0;
}
if ($mesid == 'unread') {
$mesid = $this->lastread;
}
if ($this->moved_id || !KunenaUserHelper::getMyself()->isModerator($this->getCategory())) {
if ($mesid == 'first' || $mesid == $this->first_post_id) {
return $direction == 'asc' ? 0 : $this->posts - 1;
}
if ($mesid == 'last' || $mesid == $this->last_post_id) {
return $direction == 'asc' ? $this->posts - 1 : 0;
}
if ($mesid == $this->unread) {
return $direction == 'asc' ? $this->posts - max($this->unread, 1) : 0;
}
}
if ($mesid == 'first') {
$direction = ($direction == 'asc' ? 0 : 'both');
}
if ($mesid == 'last') {
$direction = ($direction == 'asc' ? 'both' : 0);
}
return KunenaMessageHelper::getLocation($mesid, $direction, $hold);
}
/**
* @param mixed $user user
*
* @return KunenaTopicUser
*
* @throws Exception
* @since Kunena 6.0
*/
public function getUserInfo($user = null): KunenaTopicUser
{
return KunenaTopicUserHelper::get($this->id, $user);
}
/**
* @return KunenaUser
*
* @throws Exception
* @since Kunena 6.0
*/
public function getFirstPostAuthor(): KunenaUser
{
return KunenaUserHelper::getAuthor($this->first_post_userid, $this->first_post_guest_name);
}
/**
* @return KunenaUser
*
* @throws Exception
* @since Kunena 6.0
*/
public function getLastPostAuthor(): KunenaUser
{
return KunenaUserHelper::getAuthor($this->last_post_userid, $this->last_post_guest_name);
}
/**
* @return KunenaDate
*
* @since Kunena 6.0
*/
public function getFirstPostTime(): KunenaDate
{
return new KunenaDate($this->first_post_time);
}
/**
* @return KunenaDate
*
* @since Kunena 6.0
*/
public function getLastPostTime(): KunenaDate
{
return new KunenaDate($this->last_post_time);
}
/**
* Resolve/get current topic.
*
* @return KunenaTopic Returns this topic or move target if this was moved.
*
* @throws Exception
* @since Kunena 4.0
*/
public function getTopic(): KunenaTopic
{
$ids = [];
$topic = $this;
// If topic has been moved, find the new topic
while ($topic->moved_id) {
if (isset($ids[$topic->moved_id])) {
throw new RuntimeException(Text::_('COM_KUNENA_VIEW_TOPIC_ERROR_LOOP'), 500);
}
$ids[$topic->moved_id] = 1;
$topic = KunenaTopicHelper::get($topic->moved_id);
}
return $topic;
}
/**
* @param string $field field
*
* @return integer|string
*
* @throws Exception
* @since Kunena 6.0
*/
public function displayField(string $field)
{
switch ($field) {
case 'id':
return \intval($this->id);
case 'subject':
return KunenaParser::parseText($this->subject);
}
return '';
}
/**
* @param string $category_icon icon
*
* @return string
*
* @throws Exception
* @since Kunena 6.0
*/
public function getIcon($category_icon = ''): string
{
return KunenaFactory::getTemplate()->getTopicIcon($this);
}
/**
* @param mixed $hold hold
*
* @return integer
*
* @throws Exception
* @since Kunena 6.0
*/
public function getReplies($hold = null): int
{
return (int) max($this->getTotal($hold) - 1, 0);
}
/**
* @param mixed $hold hold
*
* @return integer
*
* @throws Exception
* @since Kunena 6.0
*/
public function getTotal($hold = null): int
{
if ($this->moved_id || !KunenaUserHelper::getMyself()->isModerator($this->getCategory())) {
return (int) max($this->posts, 0);
}
return KunenaMessageHelper::getLocation($this->last_post_id, 'both', $hold) + 1;
}
/**
* Get permament topic URL without domain.
*
* If you want to add domain (for email etc), you can prepend the output with this:
* Uri::getInstance()->toString(array('scheme', 'host', 'port'))
*
* @param KunenaCategory $category category
* @param bool $xhtml xhtml
* @param string $action action
*
* @return boolean
*
* @throws null
* @throws Exception
* @since Kunena 6.0
*/
public function getPermaUrl($category = null, $xhtml = true, $action = null)
{
return $this->getUrl($category, $xhtml, $action);
}
/**
* @param mixed $category category
* @param bool $xhtml xhtml
* @param KunenaMessage|null $action action
* @param int $itemid itemid
*
* @return boolean
*
* @throws null
* @throws Exception
* @since Kunena 6.0
*/
public function getUrl($category = null, $xhtml = true, $action = null, $itemid = 0)
{
return KunenaRoute::getTopicUrl(
$this,
$xhtml,
$action,
$category ? KunenaCategoryHelper::get($category) : $this->getCategory(),
$itemid
);
}
/**
* Get published state in text.
*
* @return string
*
* @since Kunena 4.0
*/
public function getState(): string
{
switch ($this->hold) {
case 0:
return 'published';
case 1:
return 'unapproved';
case 2:
case 3:
return 'deleted';
}
return 'unknown';
}
/**
* @param array|bool $fields fields
* @param mixed $user user
* @param array|void $safefields safefields
*
* @return KunenaMessage
*
* @throws null
* @since Kunena 6.0
*/
public function newReply($fields = [], $user = null, $safefields = null): KunenaMessage
{
$user = KunenaUserHelper::get($user);
$category = $this->getCategory();
$message = new KunenaMessage();
$message->setTopic($this);
$message->parent = $this->first_post_id;
$message->thread = $this->id;
$message->catid = $this->category_id;
$message->name = $user->getName('');
$message->userid = $user->userid;
$message->subject = $this->subject;
$message->ip = !empty(KunenaUserHelper::getUserIp()) ? KunenaUserHelper::getUserIp() : '';
if ($this->hold) {
// If topic was unapproved or deleted, use the same state for the new message
$message->hold = $this->hold;
} else {
// Otherwise message is either unapproved or published depending if the category is moderated or not
$message->hold = $category->review ? (int) !$category->isAuthorised('moderate', $user) : 0;
}
if ($fields === true) {
$user = KunenaUserHelper::get($this->first_post_userid);
$text = preg_replace('/\[confidential\](.*?)\[\/confidential\]/su', '', $this->first_post_message);
$message->message = "[quote=\"{$user->getName($this->first_post_guest_name)}\" post={$this->first_post_id}]" . $text . "[/quote]";
} else {
if ($safefields) {
$message->bind($safefields);
}
if ($fields) {
$message->bind($fields, ['name', 'email', 'subject', 'message'], true);
}
}
return $message;
}
/**
* @param mixed $user user
*
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function hasNew($user = null): bool
{
$user = KunenaUserHelper::get($user);
if (!KunenaFactory::getConfig()->showNew || !$user->exists()) {
return false;
}
$session = KunenaFactory::getSession();
if ($this->last_post_time <= $session->getAllReadTime()) {
return false;
}
$userinfo = KunenaCategoryUserHelper::get($this->getCategory(), $user);
if ($userinfo->allreadtime && $this->last_post_time <= $userinfo->allreadtime) {
return false;
}
$read = KunenaTopicUserReadHelper::get($this, $user);
if ($this->last_post_time <= $read->time) {
return false;
}
return true;
}
/**
* @param mixed $user user
*
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function markRead($user = null): bool
{
$user = KunenaUserHelper::get($user);
if (!KunenaFactory::getConfig()->showNew || !$user->exists() || Factory::getApplication()->getIdentity()->guest) {
return false;
}
$read = KunenaTopicUserReadHelper::get($this, $user);
$read->time = Factory::getDate()->toUnix();
$read->message_id = $this->last_post_id;
$read->save();
return true;
}
/**
* Returns true if user is authorised to do the action.
*
* @param string $action action
* @param KunenaUser|null $user user
*
* @return boolean
*
* @throws Exception
* @since Kunena 4.0
*/
public function isAuthorised($action = 'read', ?KunenaUser $user = null): bool
{
if (KunenaFactory::getConfig()->readOnly) {
// Special case to ignore authorisation.
if ($action != 'read') {
return false;
}
}
return !$this->tryAuthorise($action, $user, false);
}
/**
* Throws an exception if user isn't authorised to do the action.
*
* @param string $action action
* @param KunenaUser|null $user user
* @param bool $throw throw
*
* @return boolean
*
* @throws Exception
* @since Kunena 4.0
*/
public function tryAuthorise($action = 'read', ?KunenaUser $user = null, $throw = true)
{
// Special case to ignore authorisation.
if ($action == 'none') {
return false;
}
// Load user if not given.
if ($user === null) {
$user = KunenaUserHelper::getMyself();
}
if (empty($this->_authcache[$user->userid][$action])) {
// Unknown action - throw invalid argument exception.
if (!isset(self::$actions[$action])) {
throw new InvalidArgumentException(Text::sprintf('COM_KUNENA_LIB_AUTHORISE_INVALID_ACTION', $action), 500);
}
// Load category authorisation.
if (!isset($this->_authccache[$user->userid][$action])) {
$this->_authccache[$user->userid][$action] = $this->getCategory()->tryAuthorise('topic.' . $action, $user, false);
}
$this->_authcache[$user->userid][$action] = $this->_authccache[$user->userid][$action];
if (empty($this->_authcache[$user->userid][$action])) {
foreach (self::$actions[$action] as $function) {
if (!isset($this->_authfcache[$user->userid][$function])) {
$authFunction = 'authorise' . $function;
$this->_authfcache[$user->userid][$function] = $this->$authFunction($user);
}
$error = $this->_authfcache[$user->userid][$function];
if ($error) {
$this->_authcache[$user->userid][$action] = $error;
break;
}
}
}
}
$exception = $this->_authcache[$user->userid][$action];
// Throw or return the exception.
if ($throw && $exception) {
throw $exception;
}
return $exception;
}
/**
* Method to load a \Kunena\Forum\Libraries\Forum\Topic\Topic object by id.
*
* @param int|null $id The topic id to be loaded.
*
* @return boolean True on success.
*
* @throws Exception
* @since Kunena 6.0
*/
public function load($id = null): bool
{
$exists = parent::load($id);
$this->_hold = $this->hold === null ? 1 : $this->hold;
$this->_posts = $this->posts;
return $exists;
}
/**
* Move topic or parts of it into another category or topic.
*
* @param object $target Target \Kunena\Forum\Libraries\Forum\Category\Category or
* \Kunena\Forum\Libraries\Forum\Topic\Topic
* @param mixed $ids false, array of message Ids or Joomla\CMS\Date\Date
* @param bool $shadow Leave visible shadow topic.
* @param string $subject New subject
* @param bool $subjectall Change subject from every message
* @param int|null $topic_iconid Define a new topic icon
* @param int $keep_poll Define if you want keep the poll to the original topic or to the split topic
*
* @return boolean|KunenaCategory|KunenaTopic Target \Kunena\Forum\Libraries\Forum\Category\Category or
* \Kunena\Forum\Libraries\Forum\Topic\Topic or false on failure
* @throws Exception
* @since Kunena 6.0
*/
public function move(object $target, $ids = false, $shadow = false, $subject = '', $subjectall = false, $topic_iconid = null, $keep_poll = 0)
{
// Warning: logic in this function is very complicated and even with full understanding its easy to miss some details!
// Clear authentication cache
$this->_authfcache = $this->_authccache = $this->_authcache = [];
// Cleanup input
if (!($ids instanceof Date)) {
if (!\is_array($ids)) {
$ids = explode(',', (string) $ids);
}
$mesids = [];
foreach ($ids as $id) {
$mesids[(int) $id] = (int) $id;
}
unset($mesids[0]);
$ids = implode(',', $mesids);
}
$subject = (string) $subject;
// First we need to check if there will be messages left in the old topic
if ($ids) {
$query = $this->_db->createQuery();
$query->select('COUNT(*)')
->from($this->_db->quoteName('#__kunena_messages'))
->where($this->_db->quoteName('thread') . ' = ' . $this->_db->quote($this->id));
if ($ids instanceof Date) {
// All older messages will remain (including unapproved, deleted)
$query->where($this->_db->quoteName('time') . ' < ' . $this->_db->quote($ids->toUnix()));
} else {
// All messages that were not selected will remain
$query->where($this->_db->quoteName('id') . ' NOT IN (' . $ids . ')');
}
$this->_db->setQuery($query);
try {
$oldcount = (int) $this->_db->loadResult();
} catch (RuntimeException $e) {
$app = Factory::getApplication();
$app->enqueueMessage($e->getMessage(), 'error');
}
// So are we moving the whole topic?
if (!$oldcount) {
$ids = '';
}
}
$categoryFrom = $this->getCategory();
// Find out where we are moving the messages
if (!$target || !$target->exists()) {
throw new Exception(Text::sprintf('COM_KUNENA_MODERATION_ERROR_NO_TARGET', $this->id));
} elseif ($target instanceof KunenaTopic) {
// Move messages into another topic (original topic will always remain, either as real one or shadow)
if ($target == $this) {
// We cannot move topic into itself
throw new Exception(Text::sprintf('COM_KUNENA_MODERATION_ERROR_SAME_TARGET_THREAD', $this->id, $this->id));
}
if ($this->moved_id) {
// Moved topic cannot be merged with another topic -- it has no posts to be moved
throw new Exception(Text::sprintf('COM_KUNENA_MODERATION_ERROR_ALREADY_SHADOW', $this->id));
}
if ($this->poll_id && $target->poll_id) {
// We cannot currently have 2 polls in one topic -- fail
throw new Exception(Text::_('COM_KUNENA_MODERATION_CANNOT_MOVE_TOPIC_WITH_POLL_INTO_ANOTHER_WITH_POLL'));
}
if ($subjectall) {
$subject = $target->subject;
}
} elseif($target instanceof KunenaCategory) {
// Move messages into category
if ($target->isSection()) {
// Section cannot have any topics
throw new Exception(Text::_('COM_KUNENA_MODERATION_ERROR_NOT_MOVE_SECTION'));
}
// Save category information for later use
$categoryTarget = $target;
if ($this->moved_id) {
// Move shadow topic and we are done
$this->category_id = $categoryTarget->id;
if ($subject) {
$this->subject = $subject;
}
$this->save(false);
return $target;
}
if ($shadow || $ids) {
// Create new topic for the moved messages
$target = clone $this;
$target->exists(false);
$target->id = 0;
$target->hits = 0;
$target->params = '';
} else {
// If we just move into another category, we can keep using the old topic
$target = $this;
}
// Did user want to change the subject?
if ($subject) {
$target->subject = $subject;
}
// Did user want to change the topic icon?
if ($topic_iconid !== null) {
$target->icon_id = $topic_iconid;
}
// Did user want to change category?
$target->category_id = $categoryTarget->id;
} else {
throw new Exception(Text::_('COM_KUNENA_MODERATION_ERROR_WRONG_TARGET'));
}
// For now on we assume that at least one message will be moved (=authorization check was called on topic/message)
// We will soon need target topic id, so save if it doesn't exist
if (!$target->exists()) {
try {
$target->save(false);
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
// Move messages (set new category and topic)
$query = $this->_db->createQuery();
$query->update($this->_db->quoteName('#__kunena_messages'))
->set($this->_db->quoteName('catid') . ' = ' . $this->_db->quote($target->category_id))
->set($this->_db->quoteName('thread') . ' = ' . $this->_db->quote($target->id))
->where($this->_db->quoteName('thread') . ' = ' . $this->_db->quote($this->id));
// Did we want to change subject from all the messages?
if ($subjectall && !empty($subject)) {
$query->set($this->_db->quoteName('subject') . ' = ' . $this->_db->quote($subject));
}
if ($ids instanceof Date) {
// Move all newer messages (includes unapproved, deleted messages)
$query->where($this->_db->quoteName('time') . ' >= ' . $this->_db->quote($ids->toUnix()));
} elseif ($ids) {
// Move individual messages
$query->where($this->_db->quoteName('id') . ' IN (' . $ids . ')');
}
$this->_db->setQuery($query);
try {
$this->_db->execute();
} catch (RuntimeException $e) {
$app = Factory::getApplication();
$app->enqueueMessage($query, 'error');
}
// Make sure that all messages in topic have unique time (deterministic without ORDER BY time, id)
$query = "SET @ktime:=0";
$this->_db->setQuery($query);
try {
$this->_db->execute();
} catch (RuntimeException $e) {
$app = Factory::getApplication();
$app->enqueueMessage($e->getMessage(), 'error');
}
$query = 'UPDATE ' . $this->_db->quoteName('#__kunena_messages') . ' SET ' . $this->_db->quoteName('time') . ' = IF(time <= @ktime,@ktime:=@ktime+1,@ktime:=time) WHERE thread=' . $target->id . ' ORDER BY time ASC, id ASC';
$this->_db->setQuery($query);
try {
$this->_db->execute();
} catch (RuntimeException $e) {
$app = Factory::getApplication();
$app->enqueueMessage($e->getMessage(), 'error');
}
if ($keep_poll) {
$target->poll_id = 0;
} else {
// If all messages were moved into another topic, we need to move poll as well
if ($this->poll_id && !$ids && $target != $this) {
// Note: We may already have saved cloned target (having poll_id already in there)
$target->poll_id = $this->poll_id;
// Note: Do not remove poll from shadow: information could still be used to show icon etc
$query = $this->_db->createQuery();
$query->update($this->_db->quoteName('#__kunena_polls'))
->set($this->_db->quoteName('threadid') . ' = ' . $this->_db->quote($target->id))
->where($this->_db->quoteName('threadid') . ' = ' . $this->_db->quote($this->id));
$this->_db->setQuery($query);
try {
$this->_db->execute();
} catch (RuntimeException $e) {
$app = Factory::getApplication();
$app->enqueueMessage($e->getMessage(), 'error');
}
}
// When moving only first message keep poll only on target topic
if ($this->poll_id && $target != $this && $ids) {
if ($ids && $this->first_post_id) {
$this->poll_id = 0;
}
}
}
if (!$ids && $target != $this) {
// Leave shadow from old topic
$this->moved_id = $target->id;
if (!$shadow) {
// Mark shadow topic as deleted
$this->hold = 2;
}
}
// Note: We already saved possible target earlier, now save only $this
if (!$this->save(false)) {
return false;
}
if (!$ids && !empty($categoryTarget)) {
// Move topic into another category
// Update user topic information (topic, category)
KunenaTopicUserHelper::move($this, $target);
// TODO: do we need this?
// \Kunena\Forum\Libraries\Forum\Topic\\Kunena\Forum\Libraries\Forum\Topic\User\Read\Helper::move($this, $target);
// Remove topic and posts from the old category
$categoryFrom->update($this, -1, -$this->posts);
// Add topic and posts into the new category
$categoryTarget->update($target, 1, $this->posts);
} elseif (!$ids) {
// Moving topic into another topic
// Add new posts, hits and attachments into the target topic
$target->posts += $this->posts;
$target->hits += $this->hits;
$target->attachments += $this->attachments;
// Update first and last post information into the target topic
$target->updatePostInfo(
$this->first_post_id,
$this->first_post_time,
$this->first_post_userid,
$this->first_post_message,
$this->first_post_guest_name
);
$target->updatePostInfo(
$this->last_post_id,
$this->last_post_time,
$this->last_post_userid,
$this->last_post_message,
$this->last_post_guest_name
);
// Save target topic
try {
$target->save(false);
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
// Update user topic information (topic, category)
KunenaTopicUserHelper::merge($this, $target);
// TODO: do we need this?
// \Kunena\Forum\Libraries\Forum\Topic\\Kunena\Forum\Libraries\Forum\Topic\User\Read\Helper::merge($this, $target);
// Remove topic and posts from the old category
$this->getCategory()->update($this, -1, -$this->posts);
// Add posts into the new category
$target->getCategory()->update($target, 0, $this->posts);
} else {
// Both topics have changed and we have no idea how much: force full recount
// TODO: we can do this faster..
$this->recount();
$target->recount();
}
return $target;
}
/**
* Method to put the \Kunena\Forum\Libraries\Forum\Topic\Topic object on trash this is still present in database.
*
* @return boolean True on success.
*
* @throws Exception
* @since Kunena 6.0
*/
public function trash(): bool
{
if (!$this->exists()) {
return true;
}
// Clear authentication cache
$this->_authfcache = $this->_authccache = $this->_authcache = [];
$db = Factory::getContainer()->get('DatabaseDriver');
$queries[] = "UPDATE #__kunena_messages SET hold='2' WHERE thread={$db->quote($this->id)}";
$queries[] = "UPDATE #__kunena_topics SET hold='2' WHERE id={$db->quote($this->id)}";
foreach ($queries as $query) {
$db->setQuery($query);
try {
$this->_db->execute();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
return false;
}
}
return true;
}
/**
* @return boolean
*
* @throws Exception
* @since Kunena 6.0
*/
public function resetvotes(): bool
{
if (!$this->poll_id) {
return false;
}
$query = $this->_db->createQuery();
$query->update($this->_db->quoteName('#__kunena_polls_options'))
->set($this->_db->quoteName('votes') . ' = 0')
->where($this->_db->quoteName('pollid') . ' = ' . $this->_db->quote($this->poll_id));
$this->_db->setQuery($query);
try {
$this->_db->execute();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
return false;
}
$query = $this->_db->createQuery();
$query->delete($this->_db->quoteName('#__kunena_polls_users'))
->where($this->_db->quoteName('pollid') . ' = ' . $this->_db->quote($this->poll_id));
$this->_db->setQuery($query);
try {
$this->_db->execute();
} catch (ExecutionFailureException $e) {
KunenaError::displayDatabaseError($e);
return false;
}
return true;
}
/**
* Return the number of rating given to the topic
*
* @return integer
*
* @since Kunena 5.1.3
*/
public function getReviewCount(): int
{
return KunenaRateHelper::getCount($this->id);
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @since Kunena 6.0
*/
protected function authoriseNotExists(KunenaUser $user)
{
// Check that topic does not exist
if ($this->_exists) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_NO_ACCESS'), 403);
}
return;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @throws Exception
* @since Kunena 6.0
*/
protected function authoriseRead(KunenaUser $user)
{
// Check that user can read topic
if (!$this->exists()) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_NO_ACCESS'), 404);
}
// TODO: Allow owner to see his posts.
if ($this->hold) {
if (!$user->exists()) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_NO_ACCESS'), 401);
}
$access = KunenaAccess::getInstance();
$hold = $access->getAllowedHold($user->userid, $this->category_id, false);
if (!\in_array($this->hold, $hold)) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_NO_ACCESS'), 403);
}
}
return;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @since Kunena 6.0
*/
protected function authoriseNotHold(KunenaUser $user)
{
// Check that topic is not unapproved or deleted
if ($this->hold) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_NO_ACCESS'), 403);
}
return;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @since Kunena 6.0
*/
protected function authoriseNotMoved(KunenaUser $user)
{
// Check that topic is not moved
if ($this->moved_id) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_NO_ACCESS'), 403);
}
return;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @throws Exception
* @since Kunena 6.0
*/
protected function authoriseUnlocked(KunenaUser $user)
{
// Check that topic is not locked or user is a moderator
if ($this->locked && !$user->isModerator($this->getCategory())) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_POST_ERROR_TOPIC_LOCKED'), 403);
}
return;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @throws Exception
* @since Kunena 6.0
*/
protected function authoriseOwn(KunenaUser $user)
{
// Guests cannot own a topic.
if (!$user->exists()) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_POST_NOT_MODERATOR'), 401);
}
// Check that topic owned by the user or user is a moderator
$usertopic = $this->getUserTopic($user);
if (!$usertopic->owner && !$user->isModerator($this->getCategory())) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_POST_NOT_MODERATOR'), 403);
}
return;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @throws Exception
* @since Kunena 6.0
*/
protected function authorisePoll(KunenaUser $user)
{
// Check that user can vote
$poll = $this->getPoll();
if (!$poll->exists()) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_LIB_TOPIC_AUTHORISE_FAILED_NO_POLL'), 404);
}
return;
}
/**
* @return KunenaPoll
*
* @throws Exception
* @since Kunena 6.0
*/
public function getPoll()
{
$poll = KunenaPollHelper::get($this->poll_id);
$poll->threadid = $this->id;
return $poll;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @throws Exception
* @since Kunena 6.0
*/
protected function authoriseVote(KunenaUser $user)
{
// Check that user can vote
$config = KunenaFactory::getConfig();
$poll = $this->getPoll();
$votes = $poll->getMyVotes($user);
if (!$config->pollAllowVoteOne && $votes) {
$time_zone = Factory::getContainer()->get(SiteApplication::class)->get('offset');
$objTimeZone = new DateTimeZone($time_zone);
// Check the time between two votes
$date_a = new DateTime($poll->getMyTime(), $objTimeZone);
$date_b = new DateTime('now', $objTimeZone);
$interval = date_diff($date_a, $date_b);
if ($interval->format('%H:%I:%S') < $config->pollTimeBtVotes) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_TOPIC_VOTE_NEED_TO_WAIT_BEFORE_TO_CHANGE_VOTE'), 403);
}
}
if ($votes && $config->pollAllowVoteOne) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_LIB_TOPIC_AUTHORISE_FAILED_VOTE_ONLY_ONCE'), 403);
}
if ($votes >= $config->pollNbVotesByUser && $config->pollAllowVoteOne) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_LIB_TOPIC_AUTHORISE_FAILED_VOTE_TOO_MANY_TIMES'), 403);
}
if ($config->pollTimeBtVotes && (int) $poll->getMyTime($user) + (int) $config->pollTimeBtVotes > Factory::getDate()->toUnix()) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_LIB_TOPIC_AUTHORISE_FAILED_VOTE_TOO_EARLY'), 403);
}
if ($this->locked) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_LIB_TOPIC_AUTHORISE_FAILED_VOTE_POLL_TOPIC_LOCKED'), 403);
}
if ($poll->polltimetolive != '1000-01-01 00:00:00' && $poll->getTimeToLive() < Factory::getDate()->toUnix()) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_LIB_TOPIC_AUTHORISE_FAILED_VOTE_POLL_EXPIRED'), 403);
}
return;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @throws Exception
* @since Kunena 6.0
*/
protected function authoriseNoVotes(KunenaUser $user)
{
$poll = $this->getPoll();
$config = KunenaFactory::getConfig();
if ($poll->exists() && $poll->getUserCount() && !$config->allowEditPoll) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_LIB_TOPIC_AUTHORISE_FAILED_ONGOING_POLL'), 403);
}
return;
}
/**
* Check if user has the right to perm delete the message
*
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|bool
*
* @throws Exception
* @since Kunena 6.0
*/
protected function authorisePermdelete(KunenaUser $user)
{
$config = KunenaFactory::getConfig();
if ($user->isAdmin() || $user->isModerator()) {
return false;
}
if ($user->isModerator($this->getCategory()) && !$config->moderatorPermDelete || !$user->isModerator($this->getCategory())) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_POST_ERROR_DELETE_REPLY_AFTER'), 403);
}
return;
}
/**
* @param KunenaUser $user user
*
* @return KunenaExceptionAuthorise|void
*
* @throws Exception
* @since Kunena 6.0
*/
protected function authoriseGuestWrite(KunenaUser $user)
{
// Check if user is guest and they can create or reply topics
if ($user->userid == 0 && !KunenaFactory::getConfig()->pubWrite) {
return new KunenaExceptionAuthorise(Text::_('COM_KUNENA_POST_ERROR_ANONYMOUS_FORBITTEN'), 401);
}
return;
}
/**
* Get the table relevant properties. Override for your specific Object
*
* @return array Assocative array with the propertie values of table
*
* @since Kunena 6.4
*/
protected function getTableProperties(): array
{
$properties = [
'id' => $this->id,
'category_id' => $this->category_id,
'subject' => $this->subject,
'icon_id' => $this->icon_id,
'label_id' => $this->label_id,
'locked' => $this->locked,
'hold' => $this->hold,
'ordering' => $this->ordering,
'posts' => $this->posts,
'hits' => $this->hits,
'attachments' => $this->attachments,
'poll_id' => $this->poll_id,
'moved_id' => $this->moved_id,
'first_post_id' => $this->first_post_id,
'first_post_time' => $this->first_post_time,
'first_post_userid' => $this->first_post_userid,
'first_post_message' => $this->first_post_message,
'first_post_guest_name' => $this->first_post_guest_name,
'last_post_id' => $this->last_post_id,
'last_post_time' => $this->last_post_time,
'last_post_userid' => $this->last_post_userid,
'last_post_message' => $this->last_post_message,
'last_post_guest_name' => $this->last_post_guest_name,
'rating' => $this->rating,
'params' => $this->params,
];
return $properties;
}
}