diff --git a/lib/Alchemy/Phrasea/Application/Admin.php b/lib/Alchemy/Phrasea/Application/Admin.php index 730fbfa954..b71d1de72e 100644 --- a/lib/Alchemy/Phrasea/Application/Admin.php +++ b/lib/Alchemy/Phrasea/Application/Admin.php @@ -43,7 +43,7 @@ return call_user_func( $app->mount('/setup', new Setup()); $app->mount('/sphinx', new Sphinx()); $app->mount('/connected-users', new ConnectedUsers()); - $app->mount('/tasks', new Tasks()); + $app->mount('/tasks', new Tasks()); $app->mount('/task', new Task()); $app->mount('/scheduler', new Scheduler()); diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Scheduler.php b/lib/Alchemy/Phrasea/Controller/Admin/Scheduler.php index 397492674d..168a5bd2ba 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/Scheduler.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/Scheduler.php @@ -28,21 +28,86 @@ class Scheduler implements ControllerProviderInterface public function connect(Application $app) { $appbox = \appbox::get_instance($app['phraseanet.core']); - $session = $appbox->get_session(); $controllers = $app['controllers_factory']; /* - * route /admin/tasks/ - * tasks status in json - * or - * task manager page in html + * route /admin/scheduler/start */ - $controllers->get('/', function(Application $app, Request $request) use ($app) { - $request = $app['request']; - $task_manager = new \task_manager($appbox); + $controllers->get('/start', function(Application $app, Request $request) use ($app, $appbox) { - return ""; + $session = $appbox->get_session(); + $scheduler_key = \phrasea::scheduler_key(); + $registry = $appbox->get_registry(); + + $good_user = false; + if ($session->is_authenticated()) { + $user = \User_Adapter::getInstance($session->get_usr_id(), $appbox); + if ($user->ACL()->has_right('taskmanager')) + $good_user = true; + } + + if ( ! $good_user && (trim($scheduler_key) == '' || $scheduler_key !== $request->get('key'))) { + phrasea::headers(403); + } + + set_time_limit(0); + session_write_close(); + ignore_user_abort(true); + + $nullfile = '/dev/null'; + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $nullfile = 'NUL'; + } + + $phpcli = $registry->get('GV_cli'); + + $cmd = $phpcli . ' -f ' . $registry->get('GV_RootPath') . "bin/console scheduler:start"; + + $descriptors[1] = array("file", $nullfile, "a+"); + $descriptors[2] = array("file", $nullfile, "a+"); + + $pipes = null; + $cwd = $registry->get('GV_RootPath') . "bin/"; + $proc = proc_open($cmd, $descriptors, $pipes, $cwd, null, array('bypass_shell' => true)); + + $pid = NULL; + if (is_resource($proc)) { + $proc_status = proc_get_status($proc); + if ($proc_status['running']) + $pid = $proc_status['pid']; + } + if ($pid !== NULL) { + $msg = sprintf("scheduler '%s' started (pid=%s)", $cmd, $pid); + // my_syslog(LOG_INFO, $msg); + } else { + @fclose($pipes[1]); + @fclose($pipes[2]); + @proc_close($process); + + $msg = sprintf("scheduler '%s' failed to start", $cmd); + // my_syslog(LOG_INFO, $msg); + } + + return $app->json(true); + }); + + /* + * route /admin/scheduler/stop + */ + $controllers->get('/stop', function(Application $app, Request $request) use ($app, $appbox) { + try { + $task_manager = new \task_manager($appbox); + + $task_manager->setSchedulerState(\task_manager::STATE_TOSTOP); + + return $app->json(true); + } catch (Exception $e) { + + } + + return $app->json(false); }); return $controllers; diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Task.php b/lib/Alchemy/Phrasea/Controller/Admin/Task.php index 9c3a34f82b..23b20922f2 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/Task.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/Task.php @@ -80,6 +80,112 @@ class Task implements ControllerProviderInterface }); }); + /* + * route /admin/task/{id}/delete + * delete a task + */ + $controllers->get('/{id}/delete', function(Application $app, Request $request, $id) use ($appbox) { + $task_manager = new \task_manager($appbox); + + try { + $task = $task_manager->getTask($id); + $task->delete(); + + return $app->redirect('/admin/tasks/'); + } catch (\Exception $e) { + + /* + * todo : add a message back + */ + return $app->redirect('/admin/tasks/'); + } + }); + + /* + * route /admin/task/{id}/start + * set a task to 'tostart' + */ + $controllers->get('/{id}/tostart', function(Application $app, Request $request, $id) use ($appbox) { + $task_manager = new \task_manager($appbox); + + $ret = false; + try { + $task = $task_manager->getTask($id); + $pid = (int) ($task->getPID()); + if ( ! $pid) { + $task->setState(\task_abstract::STATE_TOSTART); + $ret = true; + } + } catch (Exception $e) { + + } + + return $app->json($ret); + }); + + /* + * route /admin/task/{id}/stop + * set a task to 'tostop' + */ + $controllers->get('/{id}/tostop', function(Application $app, Request $request, $id) use ($appbox) { + $task_manager = new \task_manager($appbox); + + $ret = false; + try { + $task = $task_manager->getTask($id); + $pid = $task->getPID(); + $signal = $request->get('signal'); + $task->setState(\task_abstract::STATE_TOSTOP); + + if ((int) $pid > 0 && (int) $signal > 0 && function_exists('posix_kill')) { + posix_kill((int) $pid, (int) $signal); + } + + $ret = true; + } catch (Exception $e) { + + } + + return $app->json($ret); + }); + + /* + * route /admin/task/{id}/resetcrashcounter + * return json + */ + $controllers->get('/{id}/resetcrashcounter', function(Application $app, Request $request, $id) use ($appbox) { + $task_manager = new \task_manager($appbox); + + try { + $task = $task_manager->getTask($id); + + $task->resetCrashCounter(); + + return $app->json(true); + } catch (\Exception $e) { + + return $app->json(false); + } + }); + + /* + * route /admin/task/{id} + * render a task editing interface + */ + $controllers->get('/{id}', function(Application $app, Request $request, $id) use ($appbox) { + + $task_manager = new \task_manager($appbox); + $task = $task_manager->getTask($id); + + /* @var $twig \Twig_Environment */ + $twig = $app['phraseanet.core']->getTwig(); + $template = 'admin/task.html'; + return $twig->render($template, array( + 'task' => $task, + 'view' => 'XML' + )); + }); + return $controllers; } } diff --git a/lib/classes/task/manager.class.php b/lib/classes/task/manager.class.php index 014f1f1135..a1ecbb03fb 100755 --- a/lib/classes/task/manager.class.php +++ b/lib/classes/task/manager.class.php @@ -36,7 +36,7 @@ class task_manager /** * status of scheduler and tasks * used do refresh the taskmanager page - * + * * @return array */ public function toArray() diff --git a/templates/web/admin/task.html.twig b/templates/web/admin/task.html.twig index 6f855b3d2c..30e69b668d 100644 --- a/templates/web/admin/task.html.twig +++ b/templates/web/admin/task.html.twig @@ -166,7 +166,7 @@ currentView : null, - oldXML:"{{task.getSettings()|stripdoublequotes}}", + oldXML:"{{task.getSettings()|escape('js')}}", view:function(type) { diff --git a/tests/Alchemy/Phrasea/Controller/Admin/TasksTest.php b/tests/Alchemy/Phrasea/Controller/Admin/TasksTest.php new file mode 100644 index 0000000000..d062baeca6 --- /dev/null +++ b/tests/Alchemy/Phrasea/Controller/Admin/TasksTest.php @@ -0,0 +1,59 @@ +client = $this->createClient(); + $this->appbox = appbox::get_instance(\bootstrap::getCore()); + } + + /** + * Default route test + */ + public function testRouteTasks() + { + $task_manager = new \task_manager($this->appbox); + + /** + * get /admin/tasks/ should return html by default + */ + $crawler = $this->client->request('GET', '/tasks/', array()); + $this->assertTrue($this->client->getResponse()->isOk()); + $this->assertCount(1, $crawler->filter('form#taskManagerForm')); + + /** + * get /admin/tasks/ can also return json + */ + $crawler = $this->client->request( + 'GET', + '/tasks/', + array(), + array(), + array('CONTENT_TYPE' => 'application/json') + ); + $this->assertTrue($this->client->getResponse()->isOk()); + $this->assertTrue($this->client->getResponse()->headers->contains('Content-Type', 'application/json')); + + $raw = $this->client->getResponse()->getContent(); + $json = json_decode($raw); + + $this->assertEquals(count($task_manager->getTasks()), count(get_object_vars($json->tasks))); + } +} diff --git a/www/admin/adminFeedback.php b/www/admin/adminFeedback.php index 332e624df1..567b09153d 100755 --- a/www/admin/adminFeedback.php +++ b/www/admin/adminFeedback.php @@ -63,7 +63,7 @@ switch ($parm['action']) { } break; - +/* case 'RESETTASKCRASHCOUNTER': $parm = $request->get_parms("task_id"); try { @@ -81,7 +81,7 @@ switch ($parm['action']) { $output = $ret->saveXML(); break; - +*/ case 'CHANGETASK': $parm = $request->get_parms('act', 'task_id', "usr"); $ret = new DOMDocument("1.0", "UTF-8"); @@ -107,6 +107,7 @@ switch ($parm['action']) { $output = $ret->saveXML(); break; +/* case 'PINGSCHEDULER_JS': $parm = $request->get_parms('dbps'); $ret = array('time' => date("H:i:s"));