[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/administrator/components/com_messages/src/Model/ -> MessageModel.php (source)

   1  <?php
   2  
   3  /**
   4   * @package     Joomla.Administrator
   5   * @subpackage  com_messages
   6   *
   7   * @copyright   (C) 2008 Open Source Matters, Inc. <https://www.joomla.org>
   8   * @license     GNU General Public License version 2 or later; see LICENSE.txt
   9   */
  10  
  11  namespace Joomla\Component\Messages\Administrator\Model;
  12  
  13  use Joomla\CMS\Access\Access;
  14  use Joomla\CMS\Access\Rule;
  15  use Joomla\CMS\Component\ComponentHelper;
  16  use Joomla\CMS\Factory;
  17  use Joomla\CMS\Language\Language;
  18  use Joomla\CMS\Language\Text;
  19  use Joomla\CMS\Log\Log;
  20  use Joomla\CMS\Mail\Exception\MailDisabledException;
  21  use Joomla\CMS\Mail\MailTemplate;
  22  use Joomla\CMS\MVC\Model\AdminModel;
  23  use Joomla\CMS\Router\Route;
  24  use Joomla\CMS\Table\Asset;
  25  use Joomla\CMS\Table\Table;
  26  use Joomla\CMS\User\User;
  27  use Joomla\Database\ParameterType;
  28  use PHPMailer\PHPMailer\Exception as phpMailerException;
  29  
  30  // phpcs:disable PSR1.Files.SideEffects
  31  \defined('_JEXEC') or die;
  32  // phpcs:enable PSR1.Files.SideEffects
  33  
  34  /**
  35   * Private Message model.
  36   *
  37   * @since  1.6
  38   */
  39  class MessageModel extends AdminModel
  40  {
  41      /**
  42       * Message
  43       *
  44       * @var    \stdClass
  45       */
  46      protected $item;
  47  
  48      /**
  49       * Method to auto-populate the model state.
  50       *
  51       * This method should only be called once per instantiation and is designed
  52       * to be called on the first call to the getState() method unless the model
  53       * configuration flag to ignore the request is set.
  54       *
  55       * Note. Calling getState in this method will result in recursion.
  56       *
  57       * @return  void
  58       *
  59       * @since   1.6
  60       */
  61      protected function populateState()
  62      {
  63          parent::populateState();
  64  
  65          $input = Factory::getApplication()->input;
  66  
  67          $user  = Factory::getUser();
  68          $this->setState('user.id', $user->get('id'));
  69  
  70          $messageId = (int) $input->getInt('message_id');
  71          $this->setState('message.id', $messageId);
  72  
  73          $replyId = (int) $input->getInt('reply_id');
  74          $this->setState('reply.id', $replyId);
  75      }
  76  
  77      /**
  78       * Check that recipient user is the one trying to delete and then call parent delete method
  79       *
  80       * @param   array  &$pks  An array of record primary keys.
  81       *
  82       * @return  boolean  True if successful, false if an error occurs.
  83       *
  84       * @since  3.1
  85       */
  86      public function delete(&$pks)
  87      {
  88          $pks   = (array) $pks;
  89          $table = $this->getTable();
  90          $user  = Factory::getUser();
  91  
  92          // Iterate the items to delete each one.
  93          foreach ($pks as $i => $pk) {
  94              if ($table->load($pk)) {
  95                  if ($table->user_id_to != $user->id) {
  96                      // Prune items that you can't change.
  97                      unset($pks[$i]);
  98  
  99                      try {
 100                          Log::add(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), Log::WARNING, 'jerror');
 101                      } catch (\RuntimeException $exception) {
 102                          Factory::getApplication()->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), 'warning');
 103                      }
 104  
 105                      return false;
 106                  }
 107              } else {
 108                  $this->setError($table->getError());
 109  
 110                  return false;
 111              }
 112          }
 113  
 114          return parent::delete($pks);
 115      }
 116  
 117      /**
 118       * Method to get a single record.
 119       *
 120       * @param   integer  $pk  The id of the primary key.
 121       *
 122       * @return  mixed    Object on success, false on failure.
 123       *
 124       * @since   1.6
 125       */
 126      public function getItem($pk = null)
 127      {
 128          if (!isset($this->item)) {
 129              if ($this->item = parent::getItem($pk)) {
 130                  // Invalid message_id returns 0
 131                  if ($this->item->user_id_to === '0') {
 132                      $this->setError(Text::_('JERROR_ALERTNOAUTHOR'));
 133  
 134                      return false;
 135                  }
 136  
 137                  // Prime required properties.
 138                  if (empty($this->item->message_id)) {
 139                      // Prepare data for a new record.
 140                      if ($replyId = (int) $this->getState('reply.id')) {
 141                          // If replying to a message, preload some data.
 142                          $db    = $this->getDatabase();
 143                          $query = $db->getQuery(true)
 144                              ->select($db->quoteName(['subject', 'user_id_from', 'user_id_to']))
 145                              ->from($db->quoteName('#__messages'))
 146                              ->where($db->quoteName('message_id') . ' = :messageid')
 147                              ->bind(':messageid', $replyId, ParameterType::INTEGER);
 148  
 149                          try {
 150                              $message = $db->setQuery($query)->loadObject();
 151                          } catch (\RuntimeException $e) {
 152                              $this->setError($e->getMessage());
 153  
 154                              return false;
 155                          }
 156  
 157                          if (!$message || $message->user_id_to != Factory::getUser()->id) {
 158                              $this->setError(Text::_('JERROR_ALERTNOAUTHOR'));
 159  
 160                              return false;
 161                          }
 162  
 163                          $this->item->set('user_id_to', $message->user_id_from);
 164                          $re = Text::_('COM_MESSAGES_RE');
 165  
 166                          if (stripos($message->subject, $re) !== 0) {
 167                              $this->item->set('subject', $re . ' ' . $message->subject);
 168                          }
 169                      }
 170                  } elseif ($this->item->user_id_to != Factory::getUser()->id) {
 171                      $this->setError(Text::_('JERROR_ALERTNOAUTHOR'));
 172  
 173                      return false;
 174                  } else {
 175                      // Mark message read
 176                      $db    = $this->getDatabase();
 177                      $query = $db->getQuery(true)
 178                          ->update($db->quoteName('#__messages'))
 179                          ->set($db->quoteName('state') . ' = 1')
 180                          ->where($db->quoteName('message_id') . ' = :messageid')
 181                          ->bind(':messageid', $this->item->message_id, ParameterType::INTEGER);
 182                      $db->setQuery($query)->execute();
 183                  }
 184              }
 185  
 186              // Get the user name for an existing message.
 187              if ($this->item->user_id_from && $fromUser = new User($this->item->user_id_from)) {
 188                  $this->item->set('from_user_name', $fromUser->name);
 189              }
 190          }
 191  
 192          return $this->item;
 193      }
 194  
 195      /**
 196       * Method to get the record form.
 197       *
 198       * @param   array    $data      Data for the form.
 199       * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
 200       *
 201       * @return  \Joomla\CMS\Form\Form|bool  A Form object on success, false on failure
 202       *
 203       * @since   1.6
 204       */
 205      public function getForm($data = array(), $loadData = true)
 206      {
 207          // Get the form.
 208          $form = $this->loadForm('com_messages.message', 'message', array('control' => 'jform', 'load_data' => $loadData));
 209  
 210          if (empty($form)) {
 211              return false;
 212          }
 213  
 214          return $form;
 215      }
 216  
 217      /**
 218       * Method to get the data that should be injected in the form.
 219       *
 220       * @return  mixed  The data for the form.
 221       *
 222       * @since   1.6
 223       */
 224      protected function loadFormData()
 225      {
 226          // Check the session for previously entered form data.
 227          $data = Factory::getApplication()->getUserState('com_messages.edit.message.data', array());
 228  
 229          if (empty($data)) {
 230              $data = $this->getItem();
 231          }
 232  
 233          $this->preprocessData('com_messages.message', $data);
 234  
 235          return $data;
 236      }
 237  
 238      /**
 239       * Checks that the current user matches the message recipient and calls the parent publish method
 240       *
 241       * @param   array    &$pks   A list of the primary keys to change.
 242       * @param   integer  $value  The value of the published state.
 243       *
 244       * @return  boolean  True on success.
 245       *
 246       * @since   3.1
 247       */
 248      public function publish(&$pks, $value = 1)
 249      {
 250          $user  = Factory::getUser();
 251          $table = $this->getTable();
 252          $pks   = (array) $pks;
 253  
 254          // Check that the recipient matches the current user
 255          foreach ($pks as $i => $pk) {
 256              $table->reset();
 257  
 258              if ($table->load($pk)) {
 259                  if ($table->user_id_to != $user->id) {
 260                      // Prune items that you can't change.
 261                      unset($pks[$i]);
 262  
 263                      try {
 264                          Log::add(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), Log::WARNING, 'jerror');
 265                      } catch (\RuntimeException $exception) {
 266                          Factory::getApplication()->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), 'warning');
 267                      }
 268  
 269                      return false;
 270                  }
 271              }
 272          }
 273  
 274          return parent::publish($pks, $value);
 275      }
 276  
 277      /**
 278       * Method to save the form data.
 279       *
 280       * @param   array  $data  The form data.
 281       *
 282       * @return  boolean  True on success.
 283       *
 284       * @since   1.6
 285       */
 286      public function save($data)
 287      {
 288          $table = $this->getTable();
 289  
 290          // Bind the data.
 291          if (!$table->bind($data)) {
 292              $this->setError($table->getError());
 293  
 294              return false;
 295          }
 296  
 297          // Assign empty values.
 298          if (empty($table->user_id_from)) {
 299              $table->user_id_from = Factory::getUser()->get('id');
 300          }
 301  
 302          if ((int) $table->date_time == 0) {
 303              $table->date_time = Factory::getDate()->toSql();
 304          }
 305  
 306          // Check the data.
 307          if (!$table->check()) {
 308              $this->setError($table->getError());
 309  
 310              return false;
 311          }
 312  
 313          // Load the user details (already valid from table check).
 314          $toUser = User::getInstance($table->user_id_to);
 315  
 316          // Check if recipient can access com_messages.
 317          if (!$toUser->authorise('core.login.admin') || !$toUser->authorise('core.manage', 'com_messages')) {
 318              $this->setError(Text::_('COM_MESSAGES_ERROR_RECIPIENT_NOT_AUTHORISED'));
 319  
 320              return false;
 321          }
 322  
 323          // Load the recipient user configuration.
 324          $model  = $this->bootComponent('com_messages')
 325              ->getMVCFactory()->createModel('Config', 'Administrator', ['ignore_request' => true]);
 326          $model->setState('user.id', $table->user_id_to);
 327          $config = $model->getItem();
 328  
 329          if (empty($config)) {
 330              $this->setError($model->getError());
 331  
 332              return false;
 333          }
 334  
 335          if ($config->get('lock', false)) {
 336              $this->setError(Text::_('COM_MESSAGES_ERR_SEND_FAILED'));
 337  
 338              return false;
 339          }
 340  
 341          // Store the data.
 342          if (!$table->store()) {
 343              $this->setError($table->getError());
 344  
 345              return false;
 346          }
 347  
 348          $key = $table->getKeyName();
 349  
 350          if (isset($table->$key)) {
 351              $this->setState($this->getName() . '.id', $table->$key);
 352          }
 353  
 354          if ($config->get('mail_on_new', true)) {
 355              $fromUser         = User::getInstance($table->user_id_from);
 356              $debug            = Factory::getApplication()->get('debug_lang');
 357              $default_language = ComponentHelper::getParams('com_languages')->get('administrator');
 358              $lang             = Language::getInstance($toUser->getParam('admin_language', $default_language), $debug);
 359              $lang->load('com_messages', JPATH_ADMINISTRATOR);
 360  
 361              // Build the email subject and message
 362              $app      = Factory::getApplication();
 363              $linkMode = $app->get('force_ssl', 0) >= 1 ? Route::TLS_FORCE : Route::TLS_IGNORE;
 364              $sitename = $app->get('sitename');
 365              $fromName = $fromUser->get('name');
 366              $siteURL  = Route::link(
 367                  'administrator',
 368                  'index.php?option=com_messages&view=message&message_id=' . $table->message_id,
 369                  false,
 370                  $linkMode,
 371                  true
 372              );
 373              $subject  = html_entity_decode($table->subject, ENT_COMPAT, 'UTF-8');
 374              $message  = strip_tags(html_entity_decode($table->message, ENT_COMPAT, 'UTF-8'));
 375  
 376              // Send the email
 377              $mailer = new MailTemplate('com_messages.new_message', $lang->getTag());
 378              $data = [
 379                  'subject' => $subject,
 380                  'message' => $message,
 381                  'fromname' => $fromName,
 382                  'sitename' => $sitename,
 383                  'siteurl' => $siteURL,
 384                  'fromemail' => $fromUser->email,
 385                  'toname' => $toUser->name,
 386                  'toemail' => $toUser->email
 387              ];
 388              $mailer->addTemplateData($data);
 389              $mailer->setReplyTo($fromUser->email, $fromUser->name);
 390              $mailer->addRecipient($toUser->email, $toUser->name);
 391  
 392              try {
 393                  $mailer->send();
 394              } catch (MailDisabledException | phpMailerException $exception) {
 395                  try {
 396                      Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror');
 397  
 398                      $this->setError(Text::_('COM_MESSAGES_ERROR_MAIL_FAILED'));
 399  
 400                      return false;
 401                  } catch (\RuntimeException $exception) {
 402                      Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning');
 403  
 404                      $this->setError(Text::_('COM_MESSAGES_ERROR_MAIL_FAILED'));
 405  
 406                      return false;
 407                  }
 408              }
 409          }
 410  
 411          return true;
 412      }
 413  
 414      /**
 415       * Sends a message to the site's super users
 416       *
 417       * @param   string  $subject  The message subject
 418       * @param   string  $message  The message
 419       *
 420       * @return  boolean
 421       *
 422       * @since   3.9.0
 423       */
 424      public function notifySuperUsers($subject, $message, $fromUser = null)
 425      {
 426          $db = $this->getDatabase();
 427  
 428          try {
 429              /** @var Asset $table */
 430              $table  = Table::getInstance('Asset');
 431              $rootId = $table->getRootId();
 432  
 433              /** @var Rule[] $rules */
 434              $rules     = Access::getAssetRules($rootId)->getData();
 435              $rawGroups = $rules['core.admin']->getData();
 436  
 437              if (empty($rawGroups)) {
 438                  $this->setError(Text::_('COM_MESSAGES_ERROR_MISSING_ROOT_ASSET_GROUPS'));
 439  
 440                  return false;
 441              }
 442  
 443              $groups = array();
 444  
 445              foreach ($rawGroups as $g => $enabled) {
 446                  if ($enabled) {
 447                      $groups[] = $g;
 448                  }
 449              }
 450  
 451              if (empty($groups)) {
 452                  $this->setError(Text::_('COM_MESSAGES_ERROR_NO_GROUPS_SET_AS_SUPER_USER'));
 453  
 454                  return false;
 455              }
 456  
 457              $query = $db->getQuery(true)
 458                  ->select($db->quoteName('map.user_id'))
 459                  ->from($db->quoteName('#__user_usergroup_map', 'map'))
 460                  ->join(
 461                      'LEFT',
 462                      $db->quoteName('#__users', 'u'),
 463                      $db->quoteName('u.id') . ' = ' . $db->quoteName('map.user_id')
 464                  )
 465                  ->whereIn($db->quoteName('map.group_id'), $groups)
 466                  ->where($db->quoteName('u.block') . ' = 0')
 467                  ->where($db->quoteName('u.sendEmail') . ' = 1');
 468  
 469              $userIDs = $db->setQuery($query)->loadColumn(0);
 470  
 471              if (empty($userIDs)) {
 472                  $this->setError(Text::_('COM_MESSAGES_ERROR_NO_USERS_SET_AS_SUPER_USER'));
 473  
 474                  return false;
 475              }
 476  
 477              foreach ($userIDs as $id) {
 478                  /*
 479                   * All messages must have a valid from user, we have use cases where an unauthenticated user may trigger this
 480                   * so we will set the from user as the to user
 481                   */
 482                  $data = [
 483                      'user_id_from' => $id,
 484                      'user_id_to'   => $id,
 485                      'subject'      => $subject,
 486                      'message'      => $message,
 487                  ];
 488  
 489                  if (!$this->save($data)) {
 490                      return false;
 491                  }
 492              }
 493  
 494              return true;
 495          } catch (\Exception $exception) {
 496              $this->setError($exception->getMessage());
 497  
 498              return false;
 499          }
 500      }
 501  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer