diff --git a/CHANGELOG.md b/CHANGELOG.md index 507e26a312..9aa3034fa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,18 @@ All notable changes to this project will be documented in this file. ## [unreleased] +### Fixed + - Changed sql query to be ansi safe + ### Added - Show locale date as tooltip for relative date time information - Add popover to counter to show voters by answer - Add forced display mode to poll configuration + ### Changed - Updated job control for the administration - Refactored some elements flex to grid + - Rearranged Job control in admin settings ## [8.5.0] - 2025-10-03 ### Fixed diff --git a/lib/Controller/AdminController.php b/lib/Controller/AdminController.php index 62d02d3862..fcf1d06297 100644 --- a/lib/Controller/AdminController.php +++ b/lib/Controller/AdminController.php @@ -9,9 +9,6 @@ namespace OCA\Polls\Controller; use OCA\Polls\AppConstants; -use OCA\Polls\Cron\AutoReminderCron; -use OCA\Polls\Cron\JanitorCron; -use OCA\Polls\Cron\NotificationCron; use OCA\Polls\Service\PollService; use OCA\Polls\Service\SystemService; use OCP\AppFramework\Http\Attribute\FrontpageRoute; @@ -36,9 +33,6 @@ public function __construct( private IURLGenerator $urlGenerator, private PollService $pollService, private IEventDispatcher $eventDispatcher, - private AutoReminderCron $autoReminderCron, - private JanitorCron $janitorCron, - private NotificationCron $notificationCron, private SystemService $systemService, ) { parent::__construct($appName, $request); @@ -71,7 +65,7 @@ public function getJobs(): JSONResponse { */ #[FrontpageRoute(verb: 'POST', url: '/administration/job/run')] public function runJob($job): JSONResponse { - return $this->response(fn () => $this->systemService->runJob($job)); + return $this->response(fn () => ['job' => $this->systemService->runJob($job)]); } /** @@ -92,28 +86,4 @@ public function takeover(int $pollId): JSONResponse { 'poll' => $this->pollService->takeover($pollId) ]); } - - /** - * Run auto reminder job - */ - #[FrontpageRoute(verb: 'GET', url: '/administration/autoreminder/run')] - public function runAutoReminderJob(): JSONResponse { - return $this->response(fn () => $this->autoReminderCron->manuallyRun()); - } - - /** - * Run janitor job - */ - #[FrontpageRoute(verb: 'GET', url: '/administration/janitor/run')] - public function runJanitorJob(): JSONResponse { - return $this->response(fn () => $this->janitorCron->manuallyRun()); - } - - /** - * Run notification job - */ - #[FrontpageRoute(verb: 'GET', url: '/administration/notification/run')] - public function runNotificationJob(): JSONResponse { - return $this->response(fn () => $this->notificationCron->manuallyRun()); - } } diff --git a/lib/Cron/AutoReminderCron.php b/lib/Cron/AutoReminderCron.php index df3e53c450..e23813c3e1 100644 --- a/lib/Cron/AutoReminderCron.php +++ b/lib/Cron/AutoReminderCron.php @@ -13,6 +13,7 @@ use OCA\Polls\Attributes\ManuallyRunnableCronJob; use OCA\Polls\Service\MailService; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\TimedJob; use OCP\ISession; use Psr\Log\LoggerInterface; @@ -20,7 +21,7 @@ * @psalm-api */ #[ManuallyRunnableCronJob] -class AutoReminderCron extends TimedCronJob { +class AutoReminderCron extends TimedJob { public function __construct( protected ITimeFactory $time, protected LoggerInterface $logger, @@ -28,7 +29,8 @@ public function __construct( private ISession $session, protected bool $supportsManualRun = true, ) { - parent::setInterval(30); // run every 30 minutes + parent::__construct($time); + parent::setInterval(300); // run every 5 minutes } /** @@ -45,10 +47,4 @@ protected function run($argument) { $this->session->remove(AppConstants::SESSION_KEY_CRON_JOB); } } - - public function manuallyRun(): string { - $this->logger->Info('AutoReminderCron will manually run.'); - $this->run(null); - return 'AutoReminderCron was manually executed.'; - } } diff --git a/lib/Cron/JanitorCron.php b/lib/Cron/JanitorCron.php index 300879b45a..181f844c7c 100644 --- a/lib/Cron/JanitorCron.php +++ b/lib/Cron/JanitorCron.php @@ -19,6 +19,8 @@ use OCA\Polls\Db\V5\TableManager; use OCA\Polls\Db\VoteMapper; use OCA\Polls\Model\Settings\AppSettings; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\TimedJob; use OCP\ISession; use Psr\Log\LoggerInterface; @@ -26,10 +28,11 @@ * @psalm-api */ #[ManuallyRunnableCronJob] -class JanitorCron extends TimedCronJob { +class JanitorCron extends TimedJob { // private AppSettings $appSettings; public function __construct( + protected ITimeFactory $time, protected LoggerInterface $logger, private ISession $session, private CommentMapper $commentMapper, @@ -42,6 +45,8 @@ public function __construct( private AppSettings $appSettings, protected bool $supportsManualRun = true, ) { + parent::__construct($time); + parent::setInterval(86400); // run once a day } /** @@ -125,11 +130,4 @@ protected function run($argument) { $this->session->remove(AppConstants::SESSION_KEY_CRON_JOB); } } - - public function manuallyRun(): string { - $this->logger->info('JanitorCron manually run.'); - $this->run(null); - return 'JanitorCron manually run.'; - } - } diff --git a/lib/Cron/NotificationCron.php b/lib/Cron/NotificationCron.php index 87115f14d5..4e6ab2685d 100644 --- a/lib/Cron/NotificationCron.php +++ b/lib/Cron/NotificationCron.php @@ -12,6 +12,8 @@ use OCA\Polls\AppConstants; use OCA\Polls\Attributes\ManuallyRunnableCronJob; use OCA\Polls\Service\MailService; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\TimedJob; use OCP\ISession; use Psr\Log\LoggerInterface; @@ -19,14 +21,15 @@ * @psalm-api */ #[ManuallyRunnableCronJob] -class NotificationCron extends TimedCronJob { +class NotificationCron extends TimedJob { public function __construct( + protected ITimeFactory $time, protected LoggerInterface $logger, private ISession $session, private MailService $mailService, protected bool $supportsManualRun = true, ) { - // parent::__construct($time); + parent::__construct($time); parent::setInterval(300); // run every 5 minutes } @@ -48,10 +51,4 @@ protected function run($argument) { } } - - public function manuallyRun(): string { - $this->logger->info('NotificationCron manually run.'); - $this->run(null); - return 'NotificationCron manually run.'; - } } diff --git a/lib/Cron/TimedCronJob.php b/lib/Cron/TimedCronJob.php deleted file mode 100644 index 5f48b42d5c..0000000000 --- a/lib/Cron/TimedCronJob.php +++ /dev/null @@ -1,43 +0,0 @@ -getName(); - - $this->logger->error('{job} does not support manual execution', ['job' => $jobClassName]); - throw new Exception('Job does not support manual execution'); - } - -} diff --git a/lib/Service/SystemService.php b/lib/Service/SystemService.php index a77350137f..600a39ea8d 100644 --- a/lib/Service/SystemService.php +++ b/lib/Service/SystemService.php @@ -11,7 +11,6 @@ use Exception; use OCA\Polls\AppConstants; use OCA\Polls\Attributes\ManuallyRunnableCronJob; -use OCA\Polls\Cron\TimedCronJob; use OCA\Polls\Db\Share; use OCA\Polls\Db\ShareMapper; use OCA\Polls\Db\UserMapper; @@ -31,7 +30,6 @@ use OCP\Collaboration\Collaborators\ISearch; use OCP\L10N\IFactory; use OCP\Share\IShare; -use phpDocumentor\Reflection\Types\This; use Psr\Log\LoggerInterface; class SystemService { @@ -271,31 +269,34 @@ public function validatePublicUsernameByToken(string $userName, string $token): * @param class-string $className The class name of the cron job to run * @throws Exception */ - public function runJob($className): string { + public function runJob($className): array { $jobs = $this->jobList->getJobsIterator($className, null, 0); foreach ($jobs as $job) { $jobClassName = get_class($job); $reflection_class = new \ReflectionClass($jobClassName); - if ($reflection_class->getNamespaceName() !== 'OCA\\Polls\\Cron') { + if ( + $reflection_class->getNamespaceName() !== 'OCA\\Polls\\Cron' + || $jobClassName !== $className + ) { continue; } - if (get_class($job) === $className) { - /** @var TimedCronJob $job */ - $job->setLastRun(time()); + $this->logger->info('{job}: started manually.', ['job' => $reflection_class->getShortName()]); + $job->setLastRun(0); + $job->start($this->jobList); + $job->setLastRun(time()); - if ( - !empty($reflection_class->getAttributes(ManuallyRunnableCronJob::class)) - && $reflection_class->hasMethod('manuallyRun') - ) { - return $job->manuallyRun(); - } else { - $this->logger->error('Job {job} does not support manual execution', ['job' => $jobClassName]); - throw new Exception('Job does not support manual execution'); - } - } + return [ + 'id' => $job->getId(), + 'className' => get_class($job), + 'lastRun' => $job->getLastRun(), + 'argument' => $job->getArgument(), + 'nameSpace' => $reflection_class->getNamespaceName(), + 'name' => $reflection_class->getShortName(), + 'manuallyRunnable' => !empty($reflection_class->getAttributes(ManuallyRunnableCronJob::class)), + ]; } throw new Exception('Job not found'); } @@ -315,7 +316,7 @@ public function getCronJobs(): array { continue; } - $joblist[] = [ + $joblist[$reflection_class->getShortName()] = [ 'id' => $job->getId(), 'className' => get_class($job), 'lastRun' => $job->getLastRun(), diff --git a/package.json b/package.json index fcbdccb32e..cc60741337 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build": "vite --mode production build", "dev": "NODE_ENV=development vite --mode development build", "dev:win": "set NODE_ENV=development && vite --mode development build", - "format": "prettier --check .", + "format": "prettier --debug-check .", "format:fix": "prettier --write .", "lint": "eslint --ext .js,.ts,.vue src", "lint:fix": "eslint --ext .js,.ts,.vue src --fix", @@ -93,4 +93,4 @@ "role": "Developer" } ] -} +} \ No newline at end of file diff --git a/src/Api/modules/admin.ts b/src/Api/modules/admin.ts index 3ccfda1249..cc228a67c8 100644 --- a/src/Api/modules/admin.ts +++ b/src/Api/modules/admin.ts @@ -8,7 +8,7 @@ import { httpInstance, createCancelTokenHandler } from './HttpApi' import type { Job, JobsList } from './api.types' const adminJobs = { - getJobsList(): Promise> { + getJobsList(): Promise> { return httpInstance.request({ method: 'GET', url: 'administration/jobs', @@ -19,7 +19,7 @@ const adminJobs = { }) }, - runJob(job: Job) { + runJob(job: Job): Promise> { return httpInstance.request({ method: 'POST', url: 'administration/job/run', diff --git a/src/Api/modules/api.types.ts b/src/Api/modules/api.types.ts index 721ad1db23..f335e195c9 100644 --- a/src/Api/modules/api.types.ts +++ b/src/Api/modules/api.types.ts @@ -18,9 +18,7 @@ export type Job = { name: string manuallyRunnable: boolean } -export type JobsList = { - jobs: Job[] -} +export type JobsList = Record export type ApiEmailAdressList = { displayName: string diff --git a/src/components/Configuration/ConfigDangerArea.vue b/src/components/Configuration/ConfigDangerArea.vue index 99cbb1b1ba..1b2a2b623d 100644 --- a/src/components/Configuration/ConfigDangerArea.vue +++ b/src/components/Configuration/ConfigDangerArea.vue @@ -6,6 +6,7 @@