3 namespace wcf\data\cronjob
;
5 use wcf\data\AbstractDatabaseObjectAction
;
6 use wcf\data\cronjob\log\CronjobLogEditor
;
7 use wcf\data\IToggleAction
;
8 use wcf\data\TDatabaseObjectToggle
;
9 use wcf\data\user\User
;
10 use wcf\system\cronjob\CronjobScheduler
;
11 use wcf\system\cronjob\ICronjob
;
12 use wcf\system\exception\PermissionDeniedException
;
14 use wcf\util\DateUtil
;
17 * Executes cronjob-related actions.
19 * @author Tim Duesterhus, Alexander Ebert
20 * @copyright 2001-2019 WoltLab GmbH
21 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
22 * @package WoltLabSuite\Core\Data\Cronjob
24 * @method Cronjob create()
25 * @method CronjobEditor[] getObjects()
26 * @method CronjobEditor getSingleObject()
28 class CronjobAction
extends AbstractDatabaseObjectAction
implements IToggleAction
30 use TDatabaseObjectToggle
;
35 protected $className = CronjobEditor
::class;
40 protected $permissionsCreate = ['admin.management.canManageCronjob'];
45 protected $permissionsDelete = ['admin.management.canManageCronjob'];
50 protected $permissionsUpdate = ['admin.management.canManageCronjob'];
55 protected $allowGuestAccess = ['executeCronjobs'];
60 protected $requireACP = ['create', 'delete', 'update', 'toggle', 'execute'];
65 public function validateDelete()
67 parent
::validateDelete();
69 foreach ($this->getObjects() as $cronjob) {
70 if (!$cronjob->isDeletable()) {
71 throw new PermissionDeniedException();
79 public function validateUpdate()
81 parent
::validateUpdate();
83 foreach ($this->getObjects() as $cronjob) {
84 if (!$cronjob->isEditable()) {
85 throw new PermissionDeniedException();
93 public function validateToggle()
95 parent
::validateUpdate();
97 foreach ($this->getObjects() as $cronjob) {
98 if (!$cronjob->canBeDisabled()) {
99 throw new PermissionDeniedException();
105 * Validates the 'execute' action.
107 public function validateExecute()
109 parent
::validateUpdate();
115 public function execute()
119 // switch session owner to 'system' during execution of cronjobs
120 $actualUser = WCF
::getUser();
121 WCF
::getSession()->changeUser(new User(null, ['userID' => 0, 'username' => 'System']), true);
122 WCF
::getSession()->disableUpdate();
125 foreach ($this->getObjects() as $key => $cronjob) {
126 // mark them as pending
127 $cronjob->update(['state' => Cronjob
::PENDING
]);
130 foreach ($this->getObjects() as $cronjob) {
131 // it now time for executing
132 $cronjob->update(['state' => Cronjob
::EXECUTING
]);
133 $className = $cronjob->className
;
135 /** @var ICronjob $executable */
136 $executable = new $className();
141 // check if all required options are set for cronjob to be executed
142 // note: a general log is created to avoid confusion why a cronjob
143 // apparently is not executed while that is indeed the correct internal
145 if ($cronjob->validateOptions()) {
147 $executable->execute(new Cronjob($cronjob->cronjobID
));
148 } catch (\Exception
$exception) {
152 CronjobLogEditor
::create([
153 'cronjobID' => $cronjob->cronjobID
,
154 'execTime' => TIME_NOW
,
155 'success' => $exception ?
0 : 1,
156 'error' => $exception ?
$exception->getMessage() : '',
159 // calculate next exec-time
160 $nextExec = $cronjob->getNextExec();
162 'lastExec' => TIME_NOW
,
163 'nextExec' => $nextExec,
164 'afterNextExec' => $cronjob->getNextExec($nextExec +
120),
169 if ($cronjob->failCount
< Cronjob
::MAX_FAIL_COUNT
) {
170 $data['failCount'] = $cronjob->failCount +
1;
173 // cronjob failed too often: disable it
174 if ($cronjob->failCount +
1 == Cronjob
::MAX_FAIL_COUNT
) {
175 $data['isDisabled'] = 1;
177 } // if no error: reset fail counter
179 $data['failCount'] = 0;
181 // if cronjob has been disabled because of too many
182 // failed executions, enable it again
183 if ($cronjob->failCount
== Cronjob
::MAX_FAIL_COUNT
&& $cronjob->isDisabled
) {
184 $data['isDisabled'] = 0;
188 $cronjob->update($data);
190 // build the return value
191 if ($exception === null && !$cronjob->isDisabled
) {
192 $dateTime = DateUtil
::getDateTimeByTimestamp($nextExec);
193 $return[$cronjob->cronjobID
] = [
195 'formatted' => \
str_replace(
197 DateUtil
::format($dateTime, DateUtil
::TIME_FORMAT
),
200 DateUtil
::format($dateTime, DateUtil
::DATE_FORMAT
),
201 WCF
::getLanguage()->get('wcf.date.dateTimeFormat')
208 $cronjob->update(['state' => Cronjob
::READY
]);
210 // throw exception again to show error message
216 // switch session back to the actual user
217 WCF
::getSession()->changeUser($actualUser, true);
224 * Validates the 'executeCronjobs' action.
226 public function validateExecuteCronjobs()
232 * Executes open cronjobs.
234 public function executeCronjobs()
236 // switch session owner to 'system' during execution of cronjobs
237 WCF
::getSession()->changeUser(new User(null, ['userID' => 0, 'username' => 'System']), true);
238 WCF
::getSession()->disableUpdate();
240 CronjobScheduler
::getInstance()->executeCronjobs();