Current File : /home/pacjaorg/public_html/dnpsom/plugins/system/actionlogs/actionlogs.php |
<?php
/**
* @package Joomla.Plugins
* @subpackage System.actionlogs
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\User;
use Joomla\Component\Actionlogs\Administrator\Helper\ActionlogsHelper;
use Joomla\Database\Exception\ExecutionFailureException;
use Joomla\Database\ParameterType;
/**
* Joomla! Users Actions Logging Plugin.
*
* @since 3.9.0
*/
class PlgSystemActionLogs extends CMSPlugin
{
/**
* Application object.
*
* @var JApplicationCms
* @since 3.9.0
*/
protected $app;
/**
* Database object.
*
* @var JDatabaseDriver
* @since 3.9.0
*/
protected $db;
/**
* Constructor.
*
* @param object $subject The object to observe.
* @param array $config An optional associative array of configuration settings.
*
* @since 3.9.0
*/
public function __construct(&$subject, $config)
{
parent::__construct($subject, $config);
// Import actionlog plugin group so that these plugins will be triggered for events
PluginHelper::importPlugin('actionlog');
}
/**
* Listener for the `onAfterInitialise` event
*
* @return void
*
* @since 4.0.0
*/
public function onAfterInitialise()
{
// Load plugin language files.
$this->loadLanguage();
}
/**
* Adds additional fields to the user editing form for logs e-mail notifications
*
* @param Form $form The form to be altered.
* @param mixed $data The associated data for the form.
*
* @return boolean
*
* @since 3.9.0
*
* @throws Exception
*/
public function onContentPrepareForm(Form $form, $data)
{
$formName = $form->getName();
$allowedFormNames = [
'com_users.profile',
'com_users.user',
];
if (!in_array($formName, $allowedFormNames, true))
{
return true;
}
/**
* We only allow users who has Super User permission change this setting for himself or for other users
* who has same Super User permission
*/
$user = Factory::getUser();
if (!$user->authorise('core.admin'))
{
return true;
}
// If we are on the save command, no data is passed to $data variable, we need to get it directly from request
$jformData = $this->app->input->get('jform', [], 'array');
if ($jformData && !$data)
{
$data = $jformData;
}
if (is_array($data))
{
$data = (object) $data;
}
if (empty($data->id) || !User::getInstance($data->id)->authorise('core.admin'))
{
return true;
}
Form::addFormPath(__DIR__ . '/forms');
if ((!PluginHelper::isEnabled('actionlog', 'joomla')) && (Factory::getApplication()->isClient('administrator')))
{
$form->loadFile('information', false);
return true;
}
if (!PluginHelper::isEnabled('actionlog', 'joomla'))
{
return true;
}
$form->loadFile('actionlogs', false);
}
/**
* Runs on content preparation
*
* @param string $context The context for the data
* @param object $data An object containing the data for the form.
*
* @return boolean
*
* @since 3.9.0
*/
public function onContentPrepareData($context, $data)
{
if (!in_array($context, ['com_users.profile', 'com_users.user']))
{
return true;
}
if (is_array($data))
{
$data = (object) $data;
}
if (!User::getInstance($data->id)->authorise('core.admin'))
{
return true;
}
$db = $this->db;
$id = (int) $data->id;
$query = $db->getQuery(true)
->select($db->quoteName(['notify', 'extensions']))
->from($db->quoteName('#__action_logs_users'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $id, ParameterType::INTEGER);
try
{
$values = $db->setQuery($query)->loadObject();
}
catch (ExecutionFailureException $e)
{
return false;
}
if (!$values)
{
return true;
}
$data->actionlogs = new stdClass;
$data->actionlogs->actionlogsNotify = $values->notify;
$data->actionlogs->actionlogsExtensions = $values->extensions;
if (!HTMLHelper::isRegistered('users.actionlogsNotify'))
{
HTMLHelper::register('users.actionlogsNotify', array(__CLASS__, 'renderActionlogsNotify'));
}
if (!HTMLHelper::isRegistered('users.actionlogsExtensions'))
{
HTMLHelper::register('users.actionlogsExtensions', array(__CLASS__, 'renderActionlogsExtensions'));
}
return true;
}
/**
* Runs after the HTTP response has been sent to the client and delete log records older than certain days
*
* @return void
*
* @since 3.9.0
*/
public function onAfterRespond()
{
$daysToDeleteAfter = (int) $this->params->get('logDeletePeriod', 0);
if ($daysToDeleteAfter <= 0)
{
return;
}
// The delete frequency will be once per day
$deleteFrequency = 3600 * 24;
// Do we need to run? Compare the last run timestamp stored in the plugin's options with the current
// timestamp. If the difference is greater than the cache timeout we shall not execute again.
$now = time();
$last = (int) $this->params->get('lastrun', 0);
if (abs($now - $last) < $deleteFrequency)
{
return;
}
// Update last run status
$this->params->set('lastrun', $now);
$db = $this->db;
$params = $this->params->toString('JSON');
$query = $db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('params') . ' = :params')
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
->where($db->quoteName('element') . ' = ' . $db->quote('actionlogs'))
->bind(':params', $params);
try
{
// Lock the tables to prevent multiple plugin executions causing a race condition
$db->lockTable('#__extensions');
}
catch (Exception $e)
{
// If we can't lock the tables it's too risky to continue execution
return;
}
try
{
// Update the plugin parameters
$result = $db->setQuery($query)->execute();
$this->clearCacheGroups(['com_plugins'], [0, 1]);
}
catch (Exception $exc)
{
// If we failed to execute
$db->unlockTables();
$result = false;
}
try
{
// Unlock the tables after writing
$db->unlockTables();
}
catch (Exception $e)
{
// If we can't lock the tables assume we have somehow failed
$result = false;
}
// Abort on failure
if (!$result)
{
return;
}
$daysToDeleteAfter = (int) $this->params->get('logDeletePeriod', 0);
$now = Factory::getDate()->toSql();
if ($daysToDeleteAfter > 0)
{
$days = -1 * $daysToDeleteAfter;
$query->clear()
->delete($db->quoteName('#__action_logs'))
->where($db->quoteName('log_date') . ' < ' . $query->dateAdd($db->quote($now), $days, 'DAY'));
$db->setQuery($query);
try
{
$db->execute();
}
catch (RuntimeException $e)
{
// Ignore it
return;
}
}
}
/**
* Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
*
* @param array $clearGroups The cache groups to clean
* @param array $cacheClients The cache clients (site, admin) to clean
*
* @return void
*
* @since 3.9.0
*/
private function clearCacheGroups(array $clearGroups, array $cacheClients = [0, 1])
{
foreach ($clearGroups as $group)
{
foreach ($cacheClients as $clientId)
{
try
{
$options = [
'defaultgroup' => $group,
'cachebase' => $clientId ? JPATH_ADMINISTRATOR . '/cache' :
Factory::getApplication()->get('cache_path', JPATH_SITE . '/cache'),
];
$cache = Cache::getInstance('callback', $options);
$cache->clean();
}
catch (Exception $e)
{
// Ignore it
}
}
}
}
/**
* Utility method to act on a user after it has been saved.
*
* @param array $user Holds the new user data.
* @param boolean $isNew True if a new user is stored.
* @param boolean $success True if user was successfully stored in the database.
* @param string $msg Message.
*
* @return void
*
* @since 3.9.0
*/
public function onUserAfterSave($user, $isNew, $success, $msg): void
{
if (!$success)
{
return;
}
// Clear access rights in case user groups were changed.
$userObject = new User($user['id']);
$userObject->clearAccessRights();
$authorised = $userObject->authorise('core.admin');
$userid = (int) $user['id'];
$db = $this->db;
$query = $db->getQuery(true)
->select('COUNT(*)')
->from($db->quoteName('#__action_logs_users'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $userid, ParameterType::INTEGER);
try
{
$exists = (bool) $db->setQuery($query)->loadResult();
}
catch (ExecutionFailureException $e)
{
return;
}
$query->clear();
// If preferences don't exist, insert.
if (!$exists && $authorised && isset($user['actionlogs']))
{
$notify = (int) $user['actionlogs']['actionlogsNotify'];
$values = [':userid', ':notify'];
$bind = [$userid, $notify];
$columns = ['user_id', 'notify'];
$query->bind($values, $bind, ParameterType::INTEGER);
if (isset($user['actionlogs']['actionlogsExtensions']))
{
$values[] = ':extension';
$columns[] = 'extensions';
$extension = json_encode($user['actionlogs']['actionlogsExtensions']);
$query->bind(':extension', $extension);
}
$query->insert($db->quoteName('#__action_logs_users'))
->columns($db->quoteName($columns))
->values(implode(',', $values));
}
elseif ($exists && $authorised && isset($user['actionlogs']))
{
// Update preferences.
$notify = (int) $user['actionlogs']['actionlogsNotify'];
$values = [$db->quoteName('notify') . ' = :notify'];
$query->bind(':notify', $notify, ParameterType::INTEGER);
if (isset($user['actionlogs']['actionlogsExtensions']))
{
$values[] = $db->quoteName('extensions') . ' = :extension';
$extension = json_encode($user['actionlogs']['actionlogsExtensions']);
$query->bind(':extension', $extension);
}
$query->update($db->quoteName('#__action_logs_users'))
->set($values)
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $userid, ParameterType::INTEGER);
}
elseif ($exists && !$authorised)
{
// Remove preferences if user is not authorised.
$query->delete($db->quoteName('#__action_logs_users'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $userid, ParameterType::INTEGER);
}
else
{
return;
}
try
{
$db->setQuery($query)->execute();
}
catch (ExecutionFailureException $e)
{
// Do nothing.
}
}
/**
* Removes user preferences
*
* Method is called after user data is deleted from the database
*
* @param array $user Holds the user data
* @param boolean $success True if user was successfully stored in the database
* @param string $msg Message
*
* @return void
*
* @since 3.9.0
*/
public function onUserAfterDelete($user, $success, $msg): void
{
if (!$success)
{
return;
}
$db = $this->db;
$userid = (int) $user['id'];
$query = $db->getQuery(true)
->delete($db->quoteName('#__action_logs_users'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $userid, ParameterType::INTEGER);
try
{
$db->setQuery($query)->execute();
}
catch (ExecutionFailureException $e)
{
// Do nothing.
}
}
/**
* Method to render a value.
*
* @param integer|string $value The value (0 or 1).
*
* @return string The rendered value.
*
* @since 3.9.16
*/
public static function renderActionlogsNotify($value)
{
return Text::_($value ? 'JYES' : 'JNO');
}
/**
* Method to render a list of extensions.
*
* @param array|string $extensions Array of extensions or an empty string if none selected.
*
* @return string The rendered value.
*
* @since 3.9.16
*/
public static function renderActionlogsExtensions($extensions)
{
// No extensions selected.
if (!$extensions)
{
return Text::_('JNONE');
}
// Load the helper.
JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR . '/components/com_actionlogs/helpers/actionlogs.php');
foreach ($extensions as &$extension)
{
// Load extension language files and translate extension name.
ActionlogsHelper::loadTranslationFiles($extension);
$extension = Text::_($extension);
}
return implode(', ', $extensions);
}
}