├── .gitignore ├── templates └── index.twig ├── .scrutinizer.yml ├── composer.json ├── .editorconfig ├── config.php ├── phpunit.xml.dist ├── elementactions ├── TaskManager_DeleteElementAction.php └── TaskManager_RestartElementAction.php ├── LICENSE ├── translations └── nl.php ├── .travis.yml ├── consolecommands └── TaskManagerCommand.php ├── models └── TaskManagerModel.php ├── TaskManagerPlugin.php ├── controllers └── TaskManagerController.php ├── tests └── TaskManager_ModelTest.php ├── README.md └── elementtypes └── TaskManagerElementType.php /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /templates/index.twig: -------------------------------------------------------------------------------- 1 | {% extends "_layouts/elementindex" %} 2 | {% set title = "Task Manager"|t %} 3 | {% set elementType = 'TaskManager' %} 4 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | php: 3 | code_rating: true 4 | duplication: true 5 | 6 | tools: 7 | external_code_coverage: true 8 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boboldehampsink/taskmanager", 3 | "description": "Task Manager Plugin for Craft CMS", 4 | "authors": [ 5 | { 6 | "name": "Bob Olde Hampsink", 7 | "email": "b.oldehampsink@itmundi.nl", 8 | "homepage": "http://github.com/boboldehampsink", 9 | "role": "Developer" 10 | } 11 | ], 12 | "license": "MIT", 13 | "type": "craft-plugin", 14 | "require": { 15 | "composer/installers": "~1.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # For more information about the properties used in 2 | # this file, please see the EditorConfig documentation: 3 | # http://editorconfig.org/ 4 | 5 | # top-most EditorConfig file 6 | root = true 7 | 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_style = space 12 | indent_size = 2 13 | insert_final_newline = true 14 | trim_trailing_whitespace = true 15 | 16 | [*.{html,twig,css,less,scss,php}] 17 | indent_size = 4 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | 22 | [package.json] 23 | # The indent size used in the `package.json` file cannot be changed 24 | # https://github.com/npm/npm/pull/3180#issuecomment-16336516 25 | indent_size = 2 26 | indent_style = space 27 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 8 | * @license MIT 9 | * 10 | * @link http://github.com/boboldehampsink 11 | */ 12 | return array( 13 | 14 | // How long should we wait before we forfeit a task as hanging? 15 | 'taskTimeout' => 0, 16 | 17 | // At what interval should the watcher watch for new tasks? (in seconds) 18 | 'taskInterval' => 10, 19 | 20 | // Hirefire.io token 21 | 'hirefireToken' => getenv('HIREFIRE_TOKEN'), 22 | 23 | // Name of the task worker you're using (if using Heroku + Hirefire.io) 24 | 'hirefireWorker' => 'worker', 25 | ); 26 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | tests 14 | 15 | 16 | 17 | 18 | ./models 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /elementactions/TaskManager_DeleteElementAction.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 10 | * @license MIT 11 | * 12 | * @link http://github.com/boboldehampsink 13 | */ 14 | class TaskManager_DeleteElementAction extends BaseElementAction 15 | { 16 | /** 17 | * Get element action name. 18 | * 19 | * @return string 20 | */ 21 | public function getName() 22 | { 23 | return Craft::t('Delete task(s)'); 24 | } 25 | 26 | /** 27 | * Delete given task. 28 | * 29 | * @param ElementCriteriaModel $criteria 30 | * 31 | * @return bool 32 | */ 33 | public function performAction(ElementCriteriaModel $criteria) 34 | { 35 | foreach ($criteria->id as $taskId) { 36 | craft()->tasks->deleteTaskById($taskId); 37 | } 38 | 39 | $this->setMessage(Craft::t('Task(s) deleted.')); 40 | 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /elementactions/TaskManager_RestartElementAction.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 10 | * @license MIT 11 | * 12 | * @link http://github.com/boboldehampsink 13 | */ 14 | class TaskManager_RestartElementAction extends BaseElementAction 15 | { 16 | /** 17 | * Get element action name. 18 | * 19 | * @return string 20 | */ 21 | public function getName() 22 | { 23 | return Craft::t('Restart task(s)'); 24 | } 25 | 26 | /** 27 | * Restart given tasks. 28 | * 29 | * @param ElementCriteriaModel $criteria 30 | * 31 | * @return bool 32 | */ 33 | public function performAction(ElementCriteriaModel $criteria) 34 | { 35 | foreach ($criteria->id as $taskId) { 36 | craft()->tasks->rerunTaskById($taskId); 37 | } 38 | 39 | $this->setMessage(Craft::t('Task(s) restarted.')); 40 | 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Bob Olde Hampsink 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /translations/nl.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 10 | * @license MIT 11 | * 12 | * @link http://github.com/boboldehampsink 13 | */ 14 | return array( 15 | 'Task Manager' => 'Taakbeheer', 16 | 'All tasks' => 'Alle taken', 17 | 'Description' => 'Omschrijving', 18 | 'Created' => 'Aangemaakt', 19 | 'Current step' => 'Huidige stap', 20 | 'Total steps' => 'Totaal aantal stappen', 21 | 'User' => 'Gebruiker', 22 | 'Restart task(s)' => 'Herstart taken', 23 | 'Are you sure you want to restart the selected task(s)?' => 'Weet je zeker dat je de geselecteerde taken wilt herstarten?', 24 | 'Task(s) restarted' => 'Taken herstart.', 25 | 'Delete task(s)' => 'Verwijder taken', 26 | 'Are you sure you want to delete the selected task(s)?' => 'Weet je zeker dat je de geselecteerde taken wilt verwijderen?', 27 | 'Task(s) deleted' => 'Taken verwijderd.', 28 | 'Error' => 'Fout', 29 | 'Running' => 'Lopend', 30 | 'No description' => 'Geen omschrijving', 31 | ); 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # see http://about.travis-ci.org/docs/user/languages/php/ for more hints 2 | language: php 3 | 4 | # list any PHP version you want to test against 5 | php: 6 | # using major version aliases 7 | 8 | # aliased to 5.3.29 9 | - 5.3 10 | # aliased to a recent 5.4.x version 11 | - 5.4 12 | # aliased to a recent 5.5.x version 13 | - 5.5 14 | # aliased to a recent 5.6.x version 15 | - 5.6 16 | # aliased to a recent 7.x version 17 | - 7.0 18 | # aliased to a recent hhvm version 19 | - hhvm 20 | 21 | # optionally set up exclutions and allowed failures in the matrix 22 | matrix: 23 | allow_failures: 24 | - php: 7.0 25 | - php: hhvm 26 | 27 | # execute any number of scripts before the test run, custom env's are available as variables 28 | before_script: 29 | - curl -sS https://codeload.github.com/pixelandtonic/Craft-Release/zip/master > craft.zip 30 | - unzip craft.zip 31 | - rm craft.zip 32 | - mv Craft-Release-master craft 33 | - mkdir craft/config 34 | - echo " 'test');" > craft/config/db.php 35 | - mkdir craft/storage 36 | - mkdir -p craft/plugins/taskmanager 37 | - for item in *; do if [[ ! "$item" == "craft" ]]; then mv $item craft/plugins/taskmanager; fi; done 38 | - cd craft/app 39 | - composer require mockery/mockery 40 | - cd ../.. 41 | 42 | # execute tests 43 | script: phpunit --bootstrap craft/app/tests/bootstrap.php --configuration craft/plugins/taskmanager/phpunit.xml.dist --coverage-clover coverage.clover craft/plugins/taskmanager/tests 44 | 45 | # upload coverage to scrutinizer 46 | after_script: 47 | - wget https://scrutinizer-ci.com/ocular.phar 48 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 49 | -------------------------------------------------------------------------------- /consolecommands/TaskManagerCommand.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 10 | * @license MIT 11 | * 12 | * @link http://github.com/boboldehampsink 13 | */ 14 | class TaskManagerCommand extends BaseCommand 15 | { 16 | /** 17 | * Runs pending tasks. 18 | * 19 | * @return int 20 | */ 21 | public function actionRun() 22 | { 23 | Craft::log(Craft::t('Running new tasks.')); 24 | 25 | // Start running tasks 26 | craft()->tasks->runPendingTasks(); 27 | 28 | return 1; 29 | } 30 | 31 | /** 32 | * Watch for tasks and run them. 33 | */ 34 | public function actionWatch() 35 | { 36 | Craft::log(Craft::t('Watching for new tasks.')); 37 | 38 | // Keep on checking for pending tasks 39 | while (true) { 40 | 41 | // Open db connection, if closed 42 | craft()->db->setActive(true); 43 | 44 | // Reset next pending tasks cache 45 | $this->resetCraftNextPendingTasksCache(); 46 | 47 | // Start running tasks 48 | craft()->tasks->runPendingTasks(); 49 | 50 | // Close db connection, if open 51 | craft()->db->setActive(false); 52 | 53 | // Sleep a little 54 | sleep(craft()->config->get('taskInterval', 'taskManager')); 55 | } 56 | } 57 | 58 | /** 59 | * Reset craft next pending task cache using reflection. 60 | */ 61 | private function resetCraftNextPendingTasksCache() 62 | { 63 | $obj = craft()->tasks; 64 | $refObject = new \ReflectionObject($obj); 65 | $refProperty = $refObject->getProperty('_nextPendingTask'); 66 | $refProperty->setAccessible(true); 67 | $refProperty->setValue($obj, null); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /models/TaskManagerModel.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 10 | * @license MIT 11 | * 12 | * @link http://github.com/boboldehampsink 13 | */ 14 | class TaskManagerModel extends BaseElementModel 15 | { 16 | /** 17 | * Element Type. 18 | * 19 | * @var string 20 | */ 21 | protected $elementType = 'TaskManager'; 22 | 23 | /** 24 | * Define attributes. 25 | * 26 | * @return array 27 | */ 28 | protected function defineAttributes() 29 | { 30 | return array_merge(parent::defineAttributes(), array( 31 | 'level' => AttributeType::Number, 32 | 'type' => AttributeType::String, 33 | 'description' => AttributeType::String, 34 | 'parentId' => AttributeType::Mixed, 35 | 'totalSteps' => AttributeType::Number, 36 | 'currentStep' => AttributeType::Number, 37 | 'settings' => AttributeType::Mixed, 38 | 'status' => array(AttributeType::Enum, 'values' => array(TaskStatus::Pending, TaskStatus::Error, TaskStatus::Running), 'default' => TaskStatus::Pending), 39 | )); 40 | } 41 | 42 | /** 43 | * Get title. 44 | */ 45 | public function getTitle() 46 | { 47 | return !empty($this->description) ? $this->description : Craft::t('No description'); 48 | } 49 | 50 | /** 51 | * Returns the element's status. 52 | * 53 | * @return string 54 | */ 55 | public function getStatus() 56 | { 57 | switch ($this->status) { 58 | 59 | case TaskStatus::Pending: 60 | return EntryModel::PENDING; 61 | 62 | case TaskStatus::Error: 63 | return EntryModel::EXPIRED; 64 | 65 | case TaskStatus::Running: 66 | return EntryModel::LIVE; 67 | 68 | default: 69 | return EntryModel::DISABLED; 70 | 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /TaskManagerPlugin.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 10 | * @license MIT 11 | * 12 | * @link http://github.com/boboldehampsink 13 | */ 14 | class TaskManagerPlugin extends BasePlugin 15 | { 16 | /** 17 | * Get plugin name. 18 | * 19 | * @return string 20 | */ 21 | public function getName() 22 | { 23 | return Craft::t('Task Manager'); 24 | } 25 | 26 | /** 27 | * Get plugin description. 28 | * 29 | * @return string 30 | */ 31 | public function getDescription() 32 | { 33 | return Craft::t('Adds a "Task Manager" section to your CP to easily cancel or delete Craft Tasks.'); 34 | } 35 | 36 | /** 37 | * Get plugin version. 38 | * 39 | * @return string 40 | */ 41 | public function getVersion() 42 | { 43 | return '0.4.3'; 44 | } 45 | 46 | /** 47 | * Get plugin developer. 48 | * 49 | * @return string 50 | */ 51 | public function getDeveloper() 52 | { 53 | return 'Bob Olde Hampsink'; 54 | } 55 | 56 | /** 57 | * Get plugin developer url. 58 | * 59 | * @return string 60 | */ 61 | public function getDeveloperUrl() 62 | { 63 | return 'https://github.com/boboldehampsink'; 64 | } 65 | 66 | /** 67 | * Get plugin documentation url. 68 | * 69 | * @return string 70 | */ 71 | public function getDocumentationUrl() 72 | { 73 | return 'https://github.com/boboldehampsink/taskmanager'; 74 | } 75 | 76 | /** 77 | * Has Control Panel section. 78 | * 79 | * @return bool 80 | */ 81 | public function hasCpSection() 82 | { 83 | return true; 84 | } 85 | 86 | /** 87 | * Register hirefire endpoint 88 | * 89 | * @return array 90 | */ 91 | public function registerSiteRoutes() 92 | { 93 | return array( 94 | 'hirefire/(?P(.*?))/info' => array('action' => 'taskManager/getPendingTasks'), 95 | ); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /controllers/TaskManagerController.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 10 | * @license MIT 11 | * 12 | * @link http://github.com/boboldehampsink 13 | */ 14 | class TaskManagerController extends BaseController 15 | { 16 | /** 17 | * Allow anonymous access (for a cronjob perhaps). 18 | * 19 | * @var bool 20 | */ 21 | public $allowAnonymous = true; 22 | 23 | /** 24 | * Get pending tasks in Hirefire.io format 25 | * 26 | * @param array $variables 27 | * 28 | * @throws HttpException 29 | */ 30 | public function actionGetPendingTasks(array $variables = array()) 31 | { 32 | // Verify hirefire token 33 | if ($variables['token'] != craft()->config->get('hirefireToken', 'taskManager')) { 34 | throw new HttpException(400, Craft::t('Invalid Hirefire token.')); 35 | } 36 | 37 | // Return pending tasks for worker 38 | $this->returnJson(array(array( 39 | 'name' => craft()->config->get('hirefireWorker', 'taskManager'), 40 | 'quantity' => craft()->tasks->getTotalTasks(), 41 | ))); 42 | } 43 | 44 | /** 45 | * Rerun all failed tasks. 46 | */ 47 | public function actionRerunAllFailedTasks() 48 | { 49 | // Get all failed tasks 50 | $query = craft()->db->createCommand() 51 | ->select('id') 52 | ->from('tasks') 53 | ->where(array('and', 'lft = 1', 'status = :status'), array(':status' => TaskStatus::Error)); 54 | 55 | // Get all hanging? tasks 56 | if ($timeout = craft()->config->get('taskTimeout', 'taskManager')) { 57 | $query->orWhere(array('and', 'lft = 1', 'dateCreated < (NOW() - INTERVAL :seconds SECOND)'), array(':seconds' => $timeout)); 58 | } 59 | 60 | // Get all 61 | $tasks = $query->queryAll(); 62 | 63 | // Loop through failed tasks 64 | foreach ($tasks as $task) { 65 | 66 | // Rerun task 67 | craft()->tasks->rerunTaskById($task['id']); 68 | } 69 | 70 | // Run pending tasks controller 71 | craft()->runController('tasks/runPendingTasks'); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/TaskManager_ModelTest.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 12 | * @license MIT 13 | * 14 | * @link http://github.com/boboldehampsink 15 | * 16 | * @coversDefaultClass Craft\TaskManagerModel 17 | * @covers :: 18 | */ 19 | class TaskManager_ModelTest extends BaseTest 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | public static function setUpBeforeClass() 25 | { 26 | parent::setUpBeforeClass(); 27 | require_once __DIR__ . '/../models/TaskManagerModel.php'; 28 | } 29 | 30 | /** 31 | * Test getTitle. 32 | * 33 | * @covers ::getTitle 34 | */ 35 | final public function testGetTitle() 36 | { 37 | // Mock localization service 38 | $this->setMockLocalizationService(); 39 | 40 | // Set up model 41 | $model = new TaskManagerModel(); 42 | 43 | // Set description attribute 44 | $model->description = 'test'; 45 | 46 | // Assert title/description 47 | $this->assertSame($model->getTitle(), $model->description); 48 | } 49 | 50 | /** 51 | * Test getStatus. 52 | * 53 | * @covers ::getStatus 54 | * @dataProvider provideStatuses 55 | */ 56 | final public function testGetStatus($taskStatus, $elementStatus) 57 | { 58 | // Mock localization service 59 | $this->setMockLocalizationService(); 60 | 61 | // Set up model 62 | $model = new TaskManagerModel(); 63 | 64 | // Set status attribute 65 | $model->status = $taskStatus; 66 | 67 | // Assert element status 68 | $this->assertSame($model->getStatus(), $elementStatus); 69 | } 70 | 71 | /** 72 | * Mock localization service. 73 | * 74 | * @return LocalizationService 75 | */ 76 | private function setMockLocalizationService() 77 | { 78 | $mock = $this->getMockBuilder('Craft\LocalizationService') 79 | ->disableOriginalConstructor() 80 | ->getMock(); 81 | 82 | $this->setComponent(craft(), 'i18n', $mock); 83 | } 84 | 85 | /** 86 | * Provide statuses. 87 | * 88 | * @return array 89 | */ 90 | final public function provideStatuses() 91 | { 92 | return array( 93 | 'Pending' => array(TaskStatus::Pending, EntryModel::PENDING), 94 | 'Error' => array(TaskStatus::Error, EntryModel::EXPIRED), 95 | 'Running' => array(TaskStatus::Running, EntryModel::LIVE), 96 | 'Unknown' => array('unknown', EntryModel::DISABLED), 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DEPRECATED - Task Manager plugin for Craft CMS [![Build Status](https://travis-ci.org/boboldehampsink/taskmanager.svg?branch=develop)](https://travis-ci.org/boboldehampsink/taskmanager) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/boboldehampsink/taskmanager/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/boboldehampsink/taskmanager/?branch=develop) [![Code Coverage](https://scrutinizer-ci.com/g/boboldehampsink/taskmanager/badges/coverage.png?b=develop)](https://scrutinizer-ci.com/g/boboldehampsink/taskmanager/?branch=develop) [![Latest Stable Version](https://poser.pugx.org/boboldehampsink/taskmanager/v/stable)](https://packagist.org/packages/boboldehampsink/taskmanager) [![Total Downloads](https://poser.pugx.org/boboldehampsink/taskmanager/downloads)](https://packagist.org/packages/boboldehampsink/taskmanager) [![Latest Unstable Version](https://poser.pugx.org/boboldehampsink/taskmanager/v/unstable)](https://packagist.org/packages/boboldehampsink/taskmanager) [![License](https://poser.pugx.org/boboldehampsink/taskmanager/license)](https://packagist.org/packages/boboldehampsink/taskmanager) 2 | ================= 3 | 4 | Adds a "Task Manager" section to your CP to easily cancel or delete Craft Tasks. 5 | 6 | __Important__ 7 | - The plugin's folder should be named "taskmanager" 8 | 9 | Deprecated 10 | ================= 11 | 12 | With the release of Craft 3 on 4-4-2018, this plugin has been deprecated. You can still use this with Craft 2 but you are encouraged to use (and develop) a Craft 3 version. At this moment, I have no plans to do so. 13 | 14 | Features 15 | ================= 16 | - View detail task info 17 | - Cancel running tasks 18 | - Rerun running or failed tasks 19 | - If you set up a cronjob to run /actions/taskManager/rerunAllFailedTasks, you can automatically rerun failed tasks 20 | - Comes with two console commands, one to run pending tasks and one to watch for pending tasks and run them. 21 | - Has an endpoint for Hirefire, see http://support.hirefire.io/help/kb/guides/any-programming-language 22 | 23 | To run pending tasks just run 24 | 25 | ``` 26 | ./craft/app/etc/console/yiic taskmanager run 27 | ``` 28 | 29 | To watch for pending tasks and them run them, run 30 | 31 | ``` 32 | ./craft/app/etc/console/yiic taskmanager watch 33 | ``` 34 | 35 | Development 36 | ================= 37 | Run this from your Craft installation to test your changes to this plugin before submitting a Pull Request 38 | ```bash 39 | phpunit --bootstrap craft/app/tests/bootstrap.php --configuration craft/plugins/taskmanager/phpunit.xml.dist --coverage-clover coverage.clover craft/plugins/taskmanager/tests 40 | ``` 41 | 42 | Changelog 43 | ================= 44 | ### 0.4.3 ### 45 | - Added the ability to get pending tasks in Hirefire.io format 46 | - Recycle db connection 47 | 48 | ### 0.4.2 ### 49 | - Fixed bug with reading default config values 50 | 51 | ### 0.4.1 ### 52 | - Added the ability to control the watch interval via the `taskInterval` config setting 53 | 54 | ### 0.4.0 ### 55 | - Added the ability to run and watch for tasks via the command line. 56 | 57 | ### 0.3.1 ### 58 | - Updated the plugin for Craft 2.5 59 | - The hook "modifyTaskManagerAttributes" is now "defineAdditionalTaskManagerTableAttributes" 60 | - Added description and documentation url 61 | 62 | ### 0.3.0 ### 63 | - Added sources by type 64 | - Replaced action buttons by element actions 65 | - Added endpoint for rerunning all failed tasks 66 | - Added the ability to restart hanging tasks after a given timeout 67 | - Added "modifyTaskManagerSources" hook 68 | - Added "addTaskManagerActions" hook 69 | - Added "modifyTaskManagerTableAttributes" hook 70 | - Added "getTaskManagerTableAttributeHtml" hook 71 | - Added "modifyTaskManagerSortableAttributes" 72 | 73 | ### 0.2.0 ### 74 | - Added the ability to restart a task 75 | - Deleting a task is now more graceful 76 | 77 | ### 0.1.0 ### 78 | - Initial release 79 | -------------------------------------------------------------------------------- /elementtypes/TaskManagerElementType.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015, Bob Olde Hampsink 10 | * @license MIT 11 | * 12 | * @link http://github.com/boboldehampsink 13 | */ 14 | class TaskManagerElementType extends BaseElementType 15 | { 16 | /** 17 | * Returns the element type name. 18 | * 19 | * @return string 20 | */ 21 | public function getName() 22 | { 23 | return Craft::t('Task Manager'); 24 | } 25 | 26 | /** 27 | * Returns whether this element type has content. 28 | * 29 | * @return bool 30 | */ 31 | public function hasContent() 32 | { 33 | return false; 34 | } 35 | 36 | /** 37 | * Returns whether this element type has titles. 38 | * 39 | * @return bool 40 | */ 41 | public function hasTitles() 42 | { 43 | return false; 44 | } 45 | 46 | /** 47 | * Returns whether this element type has statuses. 48 | * 49 | * @return bool 50 | */ 51 | public function hasStatuses() 52 | { 53 | return true; 54 | } 55 | 56 | /** 57 | * Returns this element's statuses. 58 | * 59 | * @return array 60 | */ 61 | public function getStatuses() 62 | { 63 | return array( 64 | EntryModel::PENDING => Craft::t('Pending'), 65 | EntryModel::EXPIRED => Craft::t('Error'), 66 | EntryModel::LIVE => Craft::t('Running'), 67 | ); 68 | } 69 | 70 | /** 71 | * Return sources. 72 | * 73 | * @param string $context 74 | * 75 | * @return array 76 | */ 77 | public function getSources($context = null) 78 | { 79 | $sources = array( 80 | '*' => array( 81 | 'label' => Craft::t('All tasks'), 82 | 'criteria' => array('editable' => true), 83 | ), 84 | ); 85 | 86 | // Get sources by type 87 | $results = craft()->db->createCommand() 88 | ->select('id, type') 89 | ->from('tasks') 90 | ->order('root asc, lft asc') 91 | ->group('type') 92 | ->queryAll(); 93 | foreach ($results as $result) { 94 | $sources['type:'.$result['type']] = array( 95 | 'label' => $result['type'], 96 | 'data' => array('id' => $result['id']), 97 | 'criteria' => array('type' => $result['type'], 'editable' => true), 98 | ); 99 | } 100 | 101 | // Allow plugins to modify the sources 102 | craft()->plugins->call('modifyTaskManagerSources', array(&$sources, $context)); 103 | 104 | return $sources; 105 | } 106 | 107 | /** 108 | * @inheritDoc IElementType::getAvailableActions() 109 | * 110 | * @param string|null $source 111 | * 112 | * @return array|null 113 | */ 114 | public function getAvailableActions($source = null) 115 | { 116 | $actions = array(); 117 | 118 | $restartAction = craft()->elements->getAction('TaskManager_Restart'); 119 | $restartAction->setParams(array( 120 | 'confirmationMessage' => Craft::t('Are you sure you want to restart the selected task(s)?'), 121 | 'successMessage' => Craft::t('Task(s) restarted'), 122 | )); 123 | $actions[] = $restartAction; 124 | 125 | $deleteAction = craft()->elements->getAction('TaskManager_Delete'); 126 | $deleteAction->setParams(array( 127 | 'confirmationMessage' => Craft::t('Are you sure you want to delete the selected task(s)?'), 128 | 'successMessage' => Craft::t('Task(s) deleted'), 129 | )); 130 | $actions[] = $deleteAction; 131 | 132 | // Allow plugins to add additional actions 133 | $allPluginActions = craft()->plugins->call('addTaskManagerActions', array($source), true); 134 | 135 | foreach ($allPluginActions as $pluginActions) { 136 | $actions = array_merge($actions, $pluginActions); 137 | } 138 | 139 | return $actions; 140 | } 141 | 142 | /** 143 | * @inheritDoc IElementType::defineAvailableTableAttributes() 144 | * 145 | * @return array 146 | */ 147 | public function defineAvailableTableAttributes() 148 | { 149 | $attributes = array( 150 | 'description' => Craft::t('Description'), 151 | 'type' => Craft::t('Type'), 152 | 'dateCreated' => Craft::t('Created'), 153 | 'currentStep' => Craft::t('Current step'), 154 | 'totalSteps' => Craft::t('Total steps'), 155 | ); 156 | 157 | // Allow plugins to modify the attributes 158 | $pluginAttributes = craft()->plugins->call('defineAdditionalTaskManagerTableAttributes', array(), true); 159 | foreach ($pluginAttributes as $thisPluginAttributes) { 160 | $attributes = array_merge($attributes, $thisPluginAttributes); 161 | } 162 | 163 | return $attributes; 164 | } 165 | 166 | /** 167 | * @inheritDoc IElementType::getDefaultTableAttributes() 168 | * 169 | * @param string|null $source 170 | * 171 | * @return array 172 | */ 173 | public function getDefaultTableAttributes($source = null) 174 | { 175 | return array( 176 | 'description', 177 | 'type', 178 | 'dateCreated', 179 | 'currentStep', 180 | 'totalSteps', 181 | ); 182 | } 183 | 184 | /** 185 | * Get table attribute html. 186 | * 187 | * @param BaseElementModel $element 188 | * @param string $attribute 189 | * 190 | * @return string 191 | */ 192 | public function getTableAttributeHtml(BaseElementModel $element, $attribute) 193 | { 194 | // First give plugins a chance to set this 195 | $pluginAttributeHtml = craft()->plugins->callFirst('getTaskManagerTableAttributeHtml', array($element, $attribute), true); 196 | 197 | if ($pluginAttributeHtml !== null) { 198 | return $pluginAttributeHtml; 199 | } 200 | 201 | // Or format default 202 | return parent::getTableAttributeHtml($element, $attribute); 203 | } 204 | 205 | /** 206 | * Define sortable attributes. 207 | * 208 | * @param string $source 209 | * 210 | * @return array 211 | */ 212 | public function defineSortableAttributes($source = null) 213 | { 214 | $attributes = array( 215 | 'type' => Craft::t('Type'), 216 | 'dateCreated' => Craft::t('Created'), 217 | ); 218 | 219 | // Allow plugins to modify the attributes 220 | craft()->plugins->call('modifyTaskManagerSortableAttributes', array(&$attributes)); 221 | 222 | return $attributes; 223 | } 224 | 225 | /** 226 | * Defines any custom element criteria attributes for this element type. 227 | * 228 | * @return array 229 | */ 230 | public function defineCriteriaAttributes() 231 | { 232 | return array( 233 | 'type' => AttributeType::String, 234 | 'dateCreated' => AttributeType::DateTime, 235 | ); 236 | } 237 | 238 | /** 239 | * Modifies an element query targeting elements of this type. 240 | * 241 | * @param DbCommand $query 242 | * @param ElementCriteriaModel $criteria 243 | * 244 | * @return mixed 245 | */ 246 | public function modifyElementsQuery(DbCommand $query, ElementCriteriaModel $criteria) 247 | { 248 | // Default query 249 | $query 250 | ->select('id, currentStep, totalSteps, status, type, description, settings, dateCreated') 251 | ->from('tasks elements'); 252 | 253 | // Reset default element type query parts 254 | $query->setJoin(''); 255 | $query->setWhere('1=1'); 256 | $query->setGroup(''); 257 | unset($query->params[':locale']); 258 | unset($query->params[':elementsid1']); 259 | 260 | if ($criteria->type) { 261 | $query->andWhere(DbHelper::parseParam('type', $criteria->type, $query->params)); 262 | } 263 | 264 | // Add search capabilities 265 | if ($criteria->search) { 266 | $query->andWhere(DbHelper::parseParam('description', '*'.$criteria->search.'*', $query->params)); 267 | $criteria->search = null; 268 | } 269 | } 270 | 271 | /** 272 | * Populates an element model based on a query result. 273 | * 274 | * @param array $row 275 | * 276 | * @return array 277 | */ 278 | public function populateElementModel($row) 279 | { 280 | return TaskManagerModel::populateModel($row); 281 | } 282 | } 283 | --------------------------------------------------------------------------------