Skip to content
Snippets Groups Projects
Commit 9575bfa6 authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

make cli command "cronjobs:execute" interactive, fixes #2501

Closes #2501

Merge request studip/studip!1692
parent 16774189
No related branches found
No related tags found
No related merge requests found
...@@ -5,7 +5,11 @@ namespace Studip\Cli\Commands\Cronjobs; ...@@ -5,7 +5,11 @@ namespace Studip\Cli\Commands\Cronjobs;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
class CronjobExecute extends Command class CronjobExecute extends Command
{ {
...@@ -15,28 +19,115 @@ class CronjobExecute extends Command ...@@ -15,28 +19,115 @@ class CronjobExecute extends Command
{ {
$this->setDescription('Execute cronjob task.'); $this->setDescription('Execute cronjob task.');
$this->setHelp('This command will execute a cronjob task.'); $this->setHelp('This command will execute a cronjob task.');
$this->addArgument('task_id', InputArgument::REQUIRED, 'Id of the desired cron job');
$this->addArgument(
'task_id',
InputArgument::OPTIONAL,
'Id of the desired cron job'
);
$this->addOption(
'input',
'i',
InputOption::VALUE_NONE,
'Interactively input values (defaults to true if no task_id is given)'
);
} }
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$helper = $this->getHelper('question');
$task_id = $input->getArgument('task_id'); $task_id = $input->getArgument('task_id');
$input_values = $task_id === null || $input->getOption('input');
if ($task_id === null) {
$question = new ChoiceQuestion(
"\nWhich cronjob should be executed:\n",
$this->getCronjobTaskList()
);
$task_id = $helper->ask($input, $output, $question);
}
$task = \CronjobTask::find($task_id); $task = \CronjobTask::find($task_id);
if (!$task) { if (!$task) {
$output->writeln('<error>Unknown task id</error>'); $output->writeln('<error>Unknown task id</error>');
return Command::FAILURE; return Command::FAILURE;
} }
if (!file_exists($GLOBALS['STUDIP_BASE_PATH'] . '/' . $task->filename)) { if (!$task->valid) {
$output->writeln(sprintf('<error>Invalid task, unknown filename %s</error>', $task->filename)); $output->writeln(sprintf(
'<error>Invalid task, unknown filename %s or invalid class %s</error>',
$task->filename,
$task->class
));
return Command::FAILURE; return Command::FAILURE;
} }
require_once $GLOBALS['STUDIP_BASE_PATH'] . '/' . $task->filename;
if (!class_exists('\\' . $task->class)) { $parameters = $this->getDefaultTaskParameters($task);
fwrite(STDOUT, 'Invalid task, unknown class "' . $task->class . '"' . PHP_EOL);
$output->writeln(sprintf('<error>Invalid task, unknown class %s</error>', $task->class)); if ($input_values && count($parameters) > 0) {
return Command::FAILURE; $output->writeln("\nParameters:\n");
foreach ($task->parameters as $key => $definition) {
$description = trim($definition['description'], ' ?');
$default = trim(json_encode($definition['default'] ?? null), "'");
$label = " > {$description} [<comment>{$default}</comment>] : ";
if ($definition['type'] === 'boolean') {
$question = new ConfirmationQuestion(
$label,
$definition['default'],
'/^(y|j|1)/i'
);
} elseif ($definition['type'] === 'select' && !empty($definition['values'])) {
$question = new ChoiceQuestion(
$label,
$definition['values']
);
} else {
$question = new Question(
$label,
$definition['default']
);
if ($definition['type'] === 'integer') {
$question->setNormalizer(function ($value) {
return $value ? trim($value) : '';
})->setValidator(function ($value): int {
if (strlen($value) && !ctype_digit($value)) {
throw new \RuntimeException('Number is invalid.');
}
return $value;
});
}
}
$parameters[$key] = $helper->ask($input, $output, $question);
}
} }
$task->engage('');
$task->engage('', $parameters);
return Command::SUCCESS; return Command::SUCCESS;
} }
protected function getCronjobTaskList(): array
{
$result = [];
\CronjobTask::findEachBySQL(
function (\CronjobTask $task) use (&$result): void
{
$result[$task->id] = $task->name;
},
'1'
);
return $result;
}
private function getDefaultTaskParameters(\CronjobTask $task): array
{
$parameters = [];
foreach ($task->parameters as $key => $definition) {
$parameters[$key] = $definition['default'] ?? null;
}
return $parameters;
}
} }
...@@ -27,7 +27,7 @@ class CronjobList extends Command ...@@ -27,7 +27,7 @@ class CronjobList extends Command
$table->setStyle('compact'); $table->setStyle('compact');
$table->setHeaders(['Task-ID', 'Description']); $table->setHeaders(['Task-ID', 'Description']);
foreach ($tasks as $task) { foreach ($tasks as $task) {
if (!class_exists($task->class)) { if (!$task->valid) {
continue; continue;
} }
$description = call_user_func(['\\' . $task->class, 'getDescription']); $description = call_user_func(['\\' . $task->class, 'getDescription']);
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
* @property string execution_count database column * @property string execution_count database column
* @property string assigned_count database column * @property string assigned_count database column
* @property SimpleORMapCollection schedules has_many CronjobSchedule * @property SimpleORMapCollection schedules has_many CronjobSchedule
*
* @property string $description
* @property string $name
* @property array $parameters
*/ */
class CronjobTask extends SimpleORMap class CronjobTask extends SimpleORMap
{ {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment