[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/plugins/system/actionlogs/ -> actionlogs.php (source)

   1  <?php
   2  /**
   3   * @package     Joomla.Plugins
   4   * @subpackage  System.actionlogs
   5   *
   6   * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
   7   * @license     GNU General Public License version 2 or later; see LICENSE.txt
   8   */
   9  
  10  defined('_JEXEC') or die;
  11  
  12  use Joomla\CMS\Cache\Cache;
  13  use Joomla\CMS\Factory;
  14  use Joomla\CMS\Form\Form;
  15  use Joomla\CMS\HTML\HTMLHelper;
  16  use Joomla\CMS\Language\Text;
  17  use Joomla\CMS\Plugin\CMSPlugin;
  18  use Joomla\CMS\Plugin\PluginHelper;
  19  use Joomla\CMS\User\User;
  20  use Joomla\Component\Actionlogs\Administrator\Helper\ActionlogsHelper;
  21  use Joomla\Database\Exception\ExecutionFailureException;
  22  use Joomla\Database\ParameterType;
  23  
  24  /**
  25   * Joomla! Users Actions Logging Plugin.
  26   *
  27   * @since  3.9.0
  28   */
  29  class PlgSystemActionLogs extends CMSPlugin
  30  {
  31      /**
  32       * @var    \Joomla\CMS\Application\CMSApplication
  33       *
  34       * @since  3.9.0
  35       */
  36      protected $app;
  37  
  38      /**
  39       * @var    \Joomla\Database\DatabaseDriver
  40       *
  41       * @since  3.9.0
  42       */
  43      protected $db;
  44  
  45      /**
  46       * Constructor.
  47       *
  48       * @param   object  $subject  The object to observe.
  49       * @param   array   $config   An optional associative array of configuration settings.
  50       *
  51       * @since   3.9.0
  52       */
  53  	public function __construct(&$subject, $config)
  54      {
  55          parent::__construct($subject, $config);
  56  
  57          // Import actionlog plugin group so that these plugins will be triggered for events
  58          PluginHelper::importPlugin('actionlog');
  59      }
  60  
  61      /**
  62       * Listener for the `onAfterInitialise` event
  63       *
  64       * @return  void
  65       *
  66       * @since   4.0.0
  67       */
  68  	public function onAfterInitialise()
  69      {
  70          // Load plugin language files.
  71          $this->loadLanguage();
  72      }
  73  
  74      /**
  75       * Adds additional fields to the user editing form for logs e-mail notifications
  76       *
  77       * @param   Form   $form  The form to be altered.
  78       * @param   mixed  $data  The associated data for the form.
  79       *
  80       * @return  boolean
  81       *
  82       * @since   3.9.0
  83       *
  84       * @throws  Exception
  85       */
  86  	public function onContentPrepareForm(Form $form, $data)
  87      {
  88          $formName = $form->getName();
  89  
  90          $allowedFormNames = [
  91              'com_users.profile',
  92              'com_users.user',
  93          ];
  94  
  95          if (!in_array($formName, $allowedFormNames, true))
  96          {
  97              return true;
  98          }
  99  
 100          /**
 101           * We only allow users who have Super User permission to change this setting for themselves or for other
 102           * users who have the same Super User permission
 103           */
 104  
 105          $user = Factory::getUser();
 106  
 107          if (!$user->authorise('core.admin'))
 108          {
 109              return true;
 110          }
 111  
 112          // If we are on the save command, no data is passed to $data variable, we need to get it directly from request
 113          $jformData = $this->app->input->get('jform', [], 'array');
 114  
 115          if ($jformData && !$data)
 116          {
 117              $data = $jformData;
 118          }
 119  
 120          if (is_array($data))
 121          {
 122              $data = (object) $data;
 123          }
 124  
 125          if (empty($data->id) || !User::getInstance($data->id)->authorise('core.admin'))
 126          {
 127              return true;
 128          }
 129  
 130          Form::addFormPath(__DIR__ . '/forms');
 131  
 132          if ((!PluginHelper::isEnabled('actionlog', 'joomla')) && (Factory::getApplication()->isClient('administrator')))
 133          {
 134              $form->loadFile('information', false);
 135  
 136              return true;
 137          }
 138  
 139          if (!PluginHelper::isEnabled('actionlog', 'joomla'))
 140          {
 141              return true;
 142          }
 143  
 144          $form->loadFile('actionlogs', false);
 145  
 146          return true;
 147      }
 148  
 149      /**
 150       * Runs on content preparation
 151       *
 152       * @param   string  $context  The context for the data
 153       * @param   object  $data     An object containing the data for the form.
 154       *
 155       * @return  boolean
 156       *
 157       * @since   3.9.0
 158       */
 159  	public function onContentPrepareData($context, $data)
 160      {
 161          if (!in_array($context, ['com_users.profile', 'com_users.user']))
 162          {
 163              return true;
 164          }
 165  
 166          if (is_array($data))
 167          {
 168              $data = (object) $data;
 169          }
 170  
 171          if (!User::getInstance($data->id)->authorise('core.admin'))
 172          {
 173              return true;
 174          }
 175  
 176          $db = $this->db;
 177          $id = (int) $data->id;
 178  
 179          $query = $db->getQuery(true)
 180              ->select($db->quoteName(['notify', 'extensions']))
 181              ->from($db->quoteName('#__action_logs_users'))
 182              ->where($db->quoteName('user_id') . ' = :userid')
 183              ->bind(':userid', $id, ParameterType::INTEGER);
 184  
 185          try
 186          {
 187              $values = $db->setQuery($query)->loadObject();
 188          }
 189          catch (ExecutionFailureException $e)
 190          {
 191              return false;
 192          }
 193  
 194          if (!$values)
 195          {
 196              return true;
 197          }
 198  
 199          $data->actionlogs                       = new stdClass;
 200          $data->actionlogs->actionlogsNotify     = $values->notify;
 201          $data->actionlogs->actionlogsExtensions = $values->extensions;
 202  
 203          if (!HTMLHelper::isRegistered('users.actionlogsNotify'))
 204          {
 205              HTMLHelper::register('users.actionlogsNotify', array(__CLASS__, 'renderActionlogsNotify'));
 206          }
 207  
 208          if (!HTMLHelper::isRegistered('users.actionlogsExtensions'))
 209          {
 210              HTMLHelper::register('users.actionlogsExtensions', array(__CLASS__, 'renderActionlogsExtensions'));
 211          }
 212  
 213          return true;
 214      }
 215  
 216      /**
 217       * Runs after the HTTP response has been sent to the client and delete log records older than certain days
 218       *
 219       * @return  void
 220       *
 221       * @since   3.9.0
 222       */
 223  	public function onAfterRespond()
 224      {
 225          $daysToDeleteAfter = (int) $this->params->get('logDeletePeriod', 0);
 226  
 227          if ($daysToDeleteAfter <= 0)
 228          {
 229              return;
 230          }
 231  
 232          // The delete frequency will be once per day
 233          $deleteFrequency = 3600 * 24;
 234  
 235          // Do we need to run? Compare the last run timestamp stored in the plugin's options with the current
 236          // timestamp. If the difference is greater than the cache timeout we shall not execute again.
 237          $now  = time();
 238          $last = (int) $this->params->get('lastrun', 0);
 239  
 240          if (abs($now - $last) < $deleteFrequency)
 241          {
 242              return;
 243          }
 244  
 245          // Update last run status
 246          $this->params->set('lastrun', $now);
 247  
 248          $db     = $this->db;
 249          $params = $this->params->toString('JSON');
 250          $query  = $db->getQuery(true)
 251              ->update($db->quoteName('#__extensions'))
 252              ->set($db->quoteName('params') . ' = :params')
 253              ->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
 254              ->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
 255              ->where($db->quoteName('element') . ' = ' . $db->quote('actionlogs'))
 256              ->bind(':params', $params);
 257  
 258          try
 259          {
 260              // Lock the tables to prevent multiple plugin executions causing a race condition
 261              $db->lockTable('#__extensions');
 262          }
 263          catch (Exception $e)
 264          {
 265              // If we can't lock the tables it's too risky to continue execution
 266              return;
 267          }
 268  
 269          try
 270          {
 271              // Update the plugin parameters
 272              $result = $db->setQuery($query)->execute();
 273  
 274              $this->clearCacheGroups(['com_plugins'], [0, 1]);
 275          }
 276          catch (Exception $exc)
 277          {
 278              // If we failed to execute
 279              $db->unlockTables();
 280              $result = false;
 281          }
 282  
 283          try
 284          {
 285              // Unlock the tables after writing
 286              $db->unlockTables();
 287          }
 288          catch (Exception $e)
 289          {
 290              // If we can't lock the tables assume we have somehow failed
 291              $result = false;
 292          }
 293  
 294          // Abort on failure
 295          if (!$result)
 296          {
 297              return;
 298          }
 299  
 300          $daysToDeleteAfter = (int) $this->params->get('logDeletePeriod', 0);
 301          $now               = Factory::getDate()->toSql();
 302  
 303          if ($daysToDeleteAfter > 0)
 304          {
 305              $days = -1 * $daysToDeleteAfter;
 306  
 307              $query->clear()
 308                  ->delete($db->quoteName('#__action_logs'))
 309                  ->where($db->quoteName('log_date') . ' < ' . $query->dateAdd($db->quote($now), $days, 'DAY'));
 310  
 311              $db->setQuery($query);
 312  
 313              try
 314              {
 315                  $db->execute();
 316              }
 317              catch (RuntimeException $e)
 318              {
 319                  // Ignore it
 320                  return;
 321              }
 322          }
 323      }
 324  
 325      /**
 326       * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
 327       *
 328       * @param   array  $clearGroups   The cache groups to clean
 329       * @param   array  $cacheClients  The cache clients (site, admin) to clean
 330       *
 331       * @return  void
 332       *
 333       * @since   3.9.0
 334       */
 335  	private function clearCacheGroups(array $clearGroups, array $cacheClients = [0, 1])
 336      {
 337          foreach ($clearGroups as $group)
 338          {
 339              foreach ($cacheClients as $clientId)
 340              {
 341                  try
 342                  {
 343                      $options = [
 344                          'defaultgroup' => $group,
 345                          'cachebase'    => $clientId ? JPATH_ADMINISTRATOR . '/cache' :
 346                              Factory::getApplication()->get('cache_path', JPATH_SITE . '/cache'),
 347                      ];
 348  
 349                      $cache = Cache::getInstance('callback', $options);
 350                      $cache->clean();
 351                  }
 352                  catch (Exception $e)
 353                  {
 354                      // Ignore it
 355                  }
 356              }
 357          }
 358      }
 359  
 360      /**
 361       * Utility method to act on a user after it has been saved.
 362       *
 363       * @param   array    $user     Holds the new user data.
 364       * @param   boolean  $isNew    True if a new user is stored.
 365       * @param   boolean  $success  True if user was successfully stored in the database.
 366       * @param   string   $msg      Message.
 367       *
 368       * @return  void
 369       *
 370       * @since   3.9.0
 371       */
 372  	public function onUserAfterSave($user, $isNew, $success, $msg): void
 373      {
 374          if (!$success)
 375          {
 376              return;
 377          }
 378  
 379          // Clear access rights in case user groups were changed.
 380          $userObject = new User($user['id']);
 381          $userObject->clearAccessRights();
 382  
 383          $authorised = $userObject->authorise('core.admin');
 384          $userid     = (int) $user['id'];
 385          $db         = $this->db;
 386  
 387          $query = $db->getQuery(true)
 388              ->select('COUNT(*)')
 389              ->from($db->quoteName('#__action_logs_users'))
 390              ->where($db->quoteName('user_id') . ' = :userid')
 391              ->bind(':userid', $userid, ParameterType::INTEGER);
 392  
 393          try
 394          {
 395              $exists = (bool) $db->setQuery($query)->loadResult();
 396          }
 397          catch (ExecutionFailureException $e)
 398          {
 399              return;
 400          }
 401  
 402          $query->clear();
 403  
 404          // If preferences don't exist, insert.
 405          if (!$exists && $authorised && isset($user['actionlogs']))
 406          {
 407              $notify  = (int) $user['actionlogs']['actionlogsNotify'];
 408              $values  = [':userid', ':notify'];
 409              $bind    = [$userid, $notify];
 410              $columns = ['user_id', 'notify'];
 411  
 412              $query->bind($values, $bind, ParameterType::INTEGER);
 413  
 414              if (isset($user['actionlogs']['actionlogsExtensions']))
 415              {
 416                  $values[]  = ':extension';
 417                  $columns[] = 'extensions';
 418                  $extension = json_encode($user['actionlogs']['actionlogsExtensions']);
 419                  $query->bind(':extension', $extension);
 420              }
 421  
 422              $query->insert($db->quoteName('#__action_logs_users'))
 423                  ->columns($db->quoteName($columns))
 424                  ->values(implode(',', $values));
 425          }
 426          elseif ($exists && $authorised && isset($user['actionlogs']))
 427          {
 428              // Update preferences.
 429              $notify = (int) $user['actionlogs']['actionlogsNotify'];
 430              $values = [$db->quoteName('notify') . ' = :notify'];
 431  
 432              $query->bind(':notify', $notify, ParameterType::INTEGER);
 433  
 434              if (isset($user['actionlogs']['actionlogsExtensions']))
 435              {
 436                  $values[] = $db->quoteName('extensions') . ' = :extension';
 437                  $extension = json_encode($user['actionlogs']['actionlogsExtensions']);
 438                  $query->bind(':extension', $extension);
 439              }
 440  
 441              $query->update($db->quoteName('#__action_logs_users'))
 442                  ->set($values)
 443                  ->where($db->quoteName('user_id') . ' = :userid')
 444                  ->bind(':userid', $userid, ParameterType::INTEGER);
 445          }
 446          elseif ($exists && !$authorised)
 447          {
 448              // Remove preferences if user is not authorised.
 449              $query->delete($db->quoteName('#__action_logs_users'))
 450                  ->where($db->quoteName('user_id') . ' = :userid')
 451                  ->bind(':userid', $userid, ParameterType::INTEGER);
 452          }
 453          else
 454          {
 455              return;
 456          }
 457  
 458          try
 459          {
 460              $db->setQuery($query)->execute();
 461          }
 462          catch (ExecutionFailureException $e)
 463          {
 464              // Do nothing.
 465          }
 466      }
 467  
 468      /**
 469       * Removes user preferences
 470       *
 471       * Method is called after user data is deleted from the database
 472       *
 473       * @param   array    $user     Holds the user data
 474       * @param   boolean  $success  True if user was successfully stored in the database
 475       * @param   string   $msg      Message
 476       *
 477       * @return  void
 478       *
 479       * @since   3.9.0
 480       */
 481  	public function onUserAfterDelete($user, $success, $msg): void
 482      {
 483          if (!$success)
 484          {
 485              return;
 486          }
 487  
 488          $db     = $this->db;
 489          $userid = (int) $user['id'];
 490  
 491          $query = $db->getQuery(true)
 492              ->delete($db->quoteName('#__action_logs_users'))
 493              ->where($db->quoteName('user_id') . ' = :userid')
 494              ->bind(':userid', $userid, ParameterType::INTEGER);
 495  
 496          try
 497          {
 498              $db->setQuery($query)->execute();
 499          }
 500          catch (ExecutionFailureException $e)
 501          {
 502              // Do nothing.
 503          }
 504      }
 505  
 506      /**
 507       * Method to render a value.
 508       *
 509       * @param   integer|string  $value  The value (0 or 1).
 510       *
 511       * @return  string  The rendered value.
 512       *
 513       * @since   3.9.16
 514       */
 515  	public static function renderActionlogsNotify($value)
 516      {
 517          return Text::_($value ? 'JYES' : 'JNO');
 518      }
 519  
 520      /**
 521       * Method to render a list of extensions.
 522       *
 523       * @param   array|string  $extensions  Array of extensions or an empty string if none selected.
 524       *
 525       * @return  string  The rendered value.
 526       *
 527       * @since   3.9.16
 528       */
 529  	public static function renderActionlogsExtensions($extensions)
 530      {
 531          // No extensions selected.
 532          if (!$extensions)
 533          {
 534              return Text::_('JNONE');
 535          }
 536  
 537          // Load the helper.
 538          JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR . '/components/com_actionlogs/helpers/actionlogs.php');
 539  
 540          foreach ($extensions as &$extension)
 541          {
 542              // Load extension language files and translate extension name.
 543              ActionlogsHelper::loadTranslationFiles($extension);
 544              $extension = Text::_($extension);
 545          }
 546  
 547          return implode(', ', $extensions);
 548      }
 549  }


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