### 2.2.0 Alpha 1 (XXXX-YY-ZZ)
* `options` support for cronjobs.
+* `name` attribute for cronjob PIP (`cronjobName` for cronjob objects).
* `permissions` and `options` support for event listeners.
* `name` attribute for event listener PIP (`listenerName` for event listener objects).
* `permissions` and `options` support for template listeners.
<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/cronjob.xsd">
<import>
+ <cronjob name="refreshPackageUpdates">
+ <classname><![CDATA[wcf\system\cronjob\GetUpdateInfoCronjob]]></classname>
+ <description><![CDATA[Updates package information]]></description>
+ <description language="de"><![CDATA[Aktualisiert Paket-Informationen]]></description>
+ <startminute>0</startminute>
+ <starthour>2</starthour>
+ <startdom>*/2</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="refreshSearchRobots">
+ <classname><![CDATA[wcf\system\cronjob\RefreshSearchRobotsCronjob]]></classname>
+ <description><![CDATA[Refreshes list of search robots]]></description>
+ <description language="de"><![CDATA[Aktualisiert die Liste der Suchroboter]]></description>
+ <startminute>0</startminute>
+ <starthour>3</starthour>
+ <startdom>1</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="dailyCleanUp">
+ <classname><![CDATA[wcf\system\cronjob\DailyCleanUpCronjob]]></classname>
+ <description><![CDATA[Executes daily Cleanup]]></description>
+ <description language="de"><![CDATA[Führt tägliche Aufräumarbeiten aus]]></description>
+ <startminute>0</startminute>
+ <starthour>1</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="hourlyCleanUp">
+ <classname><![CDATA[wcf\system\cronjob\HourlyCleanUpCronjob]]></classname>
+ <description><![CDATA[Executes hourly Cleanup]]></description>
+ <description language="de"><![CDATA[Führt stündliche Aufräumarbeiten aus]]></description>
+ <startminute>0</startminute>
+ <starthour>*</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="sessionCleanUp">
+ <classname><![CDATA[wcf\system\cronjob\SessionCleanUpCronjob]]></classname>
+ <description><![CDATA[Deletes expired sessions]]></description>
+ <description language="de"><![CDATA[Löscht abgelaufene Sessions]]></description>
+ <startminute>*/30</startminute>
+ <starthour>*</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="attachmentCleanUp">
+ <classname><![CDATA[wcf\system\cronjob\AttachmentCleanUpCronjob]]></classname>
+ <description><![CDATA[Deletes orphaned attachments]]></description>
+ <description language="de"><![CDATA[Löscht verwaiste Dateianhänge]]></description>
+ <startminute>0</startminute>
+ <starthour>2</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="lastActivityUpdate">
+ <classname><![CDATA[wcf\system\cronjob\LastActivityCronjob]]></classname>
+ <description><![CDATA[Updates last activity timestamp]]></description>
+ <description language="de"><![CDATA[Aktualisiert Zeitpunkt der letzten Aktivität]]></description>
+ <startminute>*/5</startminute>
+ <starthour>*</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <active>1</active>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="userQuit">
+ <classname><![CDATA[wcf\system\cronjob\UserQuitCronjob]]></classname>
+ <description><![CDATA[Deletes canceled user accounts]]></description>
+ <description language="de"><![CDATA[Löscht gekündigte Benutzer-Accounts]]></description>
+ <startminute>0</startminute>
+ <starthour>0</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <active>1</active>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="dailyMailNotification">
+ <classname><![CDATA[wcf\system\cronjob\DailyMailNotificationCronjob]]></classname>
+ <description><![CDATA[Sends daily mail notifications]]></description>
+ <description language="de"><![CDATA[Versendet tägliche E-Mail-Benachrichtigungen]]></description>
+ <startminute>*/30</startminute>
+ <starthour>*</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <active>1</active>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="moderationQueueCleanup">
+ <classname><![CDATA[wcf\system\cronjob\ModerationQueueCronjob]]></classname>
+ <description><![CDATA[Moderation queue cleanup]]></description>
+ <description language="de"><![CDATA[Löscht veraltete Einträge in der Moderation]]></description>
+ <startminute>0</startminute>
+ <starthour>1</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <active>1</active>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="statDailyBuilder">
+ <classname><![CDATA[wcf\system\cronjob\StatDailyBuilderCronjob]]></classname>
+ <description><![CDATA[Builds the daily statistics]]></description>
+ <description language="de"><![CDATA[Generiert die täglichen Statistiken]]></description>
+ <startminute>0</startminute>
+ <starthour>1</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <active>1</active>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="userGroupAssignment">
+ <classname><![CDATA[wcf\system\cronjob\UserGroupAssignmentCronjob]]></classname>
+ <description><![CDATA[Automatically assigns users to user groups]]></description>
+ <description language="de"><![CDATA[Ordnet Benutzer automatisch Benutzergruppen zu]]></description>
+ <startminute>*/30</startminute>
+ <starthour>*</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <active>1</active>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+
+ <cronjob name="userBan">
+ <classname><![CDATA[wcf\system\cronjob\UserBanCronjob]]></classname>
+ <description><![CDATA[Unbans users and enables disabled avatars and disabled signatures]]></description>
+ <description language="de"><![CDATA[Entsperrt gesperrte Benutzer, Avatare und Signaturen]]></description>
+ <startminute>0</startminute>
+ <starthour>1</starthour>
+ <startdom>*</startdom>
+ <startmonth>*</startmonth>
+ <startdow>*</startdow>
+ <active>1</active>
+ <canbeedited>1</canbeedited>
+ <canbedisabled>1</canbedisabled>
+ </cronjob>
+ </import>
+
+ <delete>
+ <!-- cronjobs with names now -->
<cronjob>
<classname><![CDATA[wcf\system\cronjob\GetUpdateInfoCronjob]]></classname>
<description><![CDATA[Updates package information]]></description>
<canbeedited>1</canbeedited>
<canbedisabled>1</canbedisabled>
</cronjob>
- </import>
-</data>
\ No newline at end of file
+ <!-- /cronjobs with names now -->
+ </delete>
+</data>
*/
const MAX_FAIL_COUNT = 3;
+ /**
+ * prefix of automatically created cronjob names
+ * @var string
+ * @deprecated will be removed once cronjob names are mandatory
+ */
+ const AUTOMATIC_NAME_PREFIX = 'com.woltlab.wcf.cronjob';
+
/**
* Returns timestamp of next execution.
*
// save cronjob description
if (!empty($descriptions)) {
- // set default value
- if (isset($descriptions[''])) {
- $defaultValue = $descriptions[''];
- }
- else if (isset($descriptions['en'])) {
- // fallback to English
- $defaultValue = $descriptions['en'];
- }
- else if (isset($descriptions[WCF::getLanguage()->getFixedLanguageCode()])) {
- // fallback to the language of the current user
- $defaultValue = $descriptions[WCF::getLanguage()->getFixedLanguageCode()];
- }
- else {
- // fallback to first description
- $defaultValue = reset($descriptions);
- }
-
- // fetch data directly from database during framework installation
- if (!PACKAGE_ID) {
- $sql = "SELECT *
- FROM wcf".WCF_N."_language_category
- WHERE languageCategory = ?";
- $statement = WCF::getDB()->prepareStatement($sql);
- $statement->execute(array('wcf.acp.cronjob'));
- $languageCategory = $statement->fetchObject('wcf\data\language\category\LanguageCategory');
-
- $languages = new LanguageList();
- $languages->readObjects();
- }
- else {
- $languages = LanguageFactory::getInstance()->getLanguages();
- $languageCategory = LanguageFactory::getInstance()->getCategory('wcf.acp.cronjob');
- }
-
- $sql = "INSERT INTO wcf".WCF_N."_language_item
- (languageID, languageItem, languageItemValue, languageCategoryID, packageID)
- VALUES (?, ?, ?, ?, ?)";
+ $cronjobEditor = new self($cronjob);
+ $cronjobEditor->saveDescriptions($descriptions, false);
+ }
+
+ return $cronjob;
+ }
+
+ /**
+ * Saves the descriptions of the cronjob in language items.
+ *
+ * @param array<string> $descriptions
+ * @param boolean $deleteOldDescriptions
+ */
+ protected function saveDescriptions(array $descriptions, $deleteOldDescriptions = true) {
+ // set default value
+ if (isset($descriptions[''])) {
+ $defaultValue = $descriptions[''];
+ }
+ else if (isset($descriptions['en'])) {
+ // fallback to English
+ $defaultValue = $descriptions['en'];
+ }
+ else if (isset($descriptions[WCF::getLanguage()->getFixedLanguageCode()])) {
+ // fallback to the language of the current user
+ $defaultValue = $descriptions[WCF::getLanguage()->getFixedLanguageCode()];
+ }
+ else {
+ // fallback to first description
+ $defaultValue = reset($descriptions);
+ }
+
+ // fetch data directly from database during framework installation
+ if (!PACKAGE_ID) {
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_language_category
+ WHERE languageCategory = ?";
$statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array('wcf.acp.cronjob'));
+ $languageCategory = $statement->fetchObject('wcf\data\language\category\LanguageCategory');
- foreach ($languages as $language) {
- $value = $defaultValue;
- if (isset($descriptions[$language->languageCode])) {
- $value = $descriptions[$language->languageCode];
- }
-
- $statement->execute(array(
- $language->languageID,
- 'wcf.acp.cronjob.description.cronjob'.$cronjob->cronjobID,
- $value,
- $languageCategory->languageCategoryID,
- $cronjob->packageID
- ));
+ $languages = new LanguageList();
+ $languages->readObjects();
+ }
+ else {
+ $languages = LanguageFactory::getInstance()->getLanguages();
+ $languageCategory = LanguageFactory::getInstance()->getCategory('wcf.acp.cronjob');
+ }
+
+ // delete old descriptions first
+ if ($deleteOldDescriptions) {
+ $sql = "DELETE FROM wcf".WCF_N."_language_item
+ WHERE languageItem = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute([ 'wcf.acp.cronjob.description.cronjob'.$this->cronjobID ]);
+ }
+
+ // save new descriptions
+ $sql = "INSERT INTO wcf".WCF_N."_language_item
+ (languageID, languageItem, languageItemValue, languageCategoryID, packageID)
+ VALUES (?, ?, ?, ?, ?)";
+ $statement = WCF::getDB()->prepareStatement($sql);
+
+ foreach ($languages as $language) {
+ $value = $defaultValue;
+ if (isset($descriptions[$language->languageCode])) {
+ $value = $descriptions[$language->languageCode];
}
- // update cronjob
- $cronjobEditor = new CronjobEditor($cronjob);
- $cronjobEditor->update(array(
- 'description' => 'wcf.acp.cronjob.description.cronjob'.$cronjob->cronjobID
+ $statement->execute(array(
+ $language->languageID,
+ 'wcf.acp.cronjob.description.cronjob'.$this->cronjobID,
+ $value,
+ $languageCategory->languageCategoryID,
+ $this->packageID
));
}
- return $cronjob;
+ // update cronjob
+ $this->update(array(
+ 'description' => 'wcf.acp.cronjob.description.cronjob'.$this->cronjobID
+ ));
+ }
+
+ /**
+ * @see \wcf\data\IEditableObject::update()
+ */
+ public function update(array $parameters = array()) {
+ $descriptions = array();
+ if (isset($parameters['description']) && is_array($parameters['description'])) {
+ if (count($parameters['description']) > 1) {
+ $descriptions = $parameters['description'];
+ $parameters['description'] = '';
+ }
+ else {
+ $parameters['description'] = reset($parameters['description']);
+ }
+ }
+
+ parent::update($parameters);
+
+ // save cronjob description
+ if (!empty($descriptions)) {
+ $this->saveDescriptions($descriptions);
+ }
}
/**
<?php
namespace wcf\system\package\plugin;
+use wcf\data\cronjob\Cronjob;
+use wcf\data\cronjob\CronjobEditor;
use wcf\system\WCF;
use wcf\util\CronjobUtil;
$sql = "DELETE FROM wcf".WCF_N."_".$this->tableName."
WHERE className = ?
AND packageID = ?";
+ $legacyStatement = WCF::getDB()->prepareStatement($sql);
+
+ $sql = "DELETE FROM wcf".WCF_N."_".$this->tableName."
+ WHERE cronjobName = ?
+ AND packageID = ?";
$statement = WCF::getDB()->prepareStatement($sql);
+
foreach ($items as $item) {
- $statement->execute(array(
- $item['elements']['classname'],
- $this->installation->getPackageID()
- ));
+ if (!isset($item['attributes']['name'])) {
+ $legacyStatement->execute(array(
+ $item['elements']['classname'],
+ $this->installation->getPackageID()
+ ));
+ }
+ else {
+ $statement->execute(array(
+ $item['attributes']['name'],
+ $this->installation->getPackageID()
+ ));
+ }
}
}
'canBeDisabled' => (isset($data['elements']['canbedisabled'])) ? intval($data['elements']['canbedisabled']) : 1,
'canBeEdited' => (isset($data['elements']['canbeedited'])) ? intval($data['elements']['canbeedited']) : 1,
'className' => (isset($data['elements']['classname'])) ? $data['elements']['classname'] : '',
+ 'cronjobName' => (isset($data['attributes']['name']) ? $data['attributes']['name'] : ''),
'description' => (isset($data['elements']['description'])) ? $data['elements']['description'] : '',
'isDisabled' => (isset($data['elements']['isdisabled'])) ? intval($data['elements']['isdisabled']) : 0,
'options' => (isset($data['elements']['options'])) ? $data['elements']['options'] : '',
CronjobUtil::validate($data['startMinute'], $data['startHour'], $data['startDom'], $data['startMonth'], $data['startDow']);
}
+ /**
+ * @see \wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::import()
+ */
+ protected function import(array $row, array $data) {
+ // if a cronjob is updated without a name given, keep the old automatically
+ // assigned name
+ if (!empty($row) && !$data['cronjobName']) {
+ unset($data['cronjobName']);
+ }
+
+ $cronjob = parent::import($row, $data);
+
+ // update event listener name
+ if (!$cronjob->cronjobName) {
+ $cronjobEditor = new CronjobEditor($cronjob);
+ $cronjobEditor->update(array(
+ 'cronjobName' => Cronjob::AUTOMATIC_NAME_PREFIX.$cronjob->cronjobID
+ ));
+
+ $cronjob = new Cronjob($cronjob->listenerID);
+ }
+
+ return $cronjob;
+ }
+
/**
* @see \wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::findExistingItem()
*/
protected function findExistingItem(array $data) {
- return null;
+ if (!$data['cronjobName']) return null;
+
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_".$this->tableName."
+ WHERE packageID = ?
+ AND cronjobName = ?";
+ $parameters = array(
+ $this->installation->getPackageID(),
+ $data['cronjobName']
+ );
+
+ return array(
+ 'sql' => $sql,
+ 'parameters' => $parameters
+ );
}
/**
cronjobID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
className varchar(255) NOT NULL DEFAULT '',
packageID INT(10) NOT NULL,
+ cronjobName VARCHAR(255) NOT NULL,
description varchar(255) NOT NULL DEFAULT '',
startMinute varchar(255) NOT NULL DEFAULT '*',
startHour varchar(255) NOT NULL DEFAULT '*',
canBeDisabled TINYINT(1) NOT NULL DEFAULT 1,
state TINYINT(1) NOT NULL DEFAULT 0,
failCount TINYINT(1) NOT NULL DEFAULT 0,
- options TEXT
+ options TEXT,
+
+ UNIQUE KEY cronjobName (cronjobName, packageID)
);
DROP TABLE IF EXISTS wcf1_cronjob_log;