elBySel('input[name=awardAutomatically]').addEventListener('change', function () {
var awardAutomatically = elBySel('input[name=awardAutomatically]').checked;
elBySelAll('.conditionSection', null, window[(awardAutomatically ? 'elShow' : 'elHide')]);
+
+ if (awardAutomatically) {
+ elShow(elById('revokeAutomaticallyDL'));
+ }
+ else {
+ elHide(elById('revokeAutomaticallyDL'));
+ }
});
BadgeHandler.init();
</dd>
</dl>
+ <dl id="revokeAutomaticallyDL"{if !$awardAutomatically} style="display: none;"{/if}>
+ <dt></dt>
+ <dd>
+ <label><input type="checkbox" name="revokeAutomatically" value="1"{if $revokeAutomatically} checked{/if}> {lang}wcf.acp.trophy.revokeAutomatically{/lang}</label>
+ </dd>
+ </dl>
+
<dl>
<dt><label for="type">{lang}wcf.acp.trophy.type{/lang}</label></dt>
<dd>
*/
public $awardAutomatically = 0;
+ /**
+ * `1` if the trophy is automatically revoked, if the conditions are not longer fulfilled
+ * @var int
+ */
+ public $revokeAutomatically = 0;
+
/**
* `1` if the trophy contains html in the description
* @var int
if (isset($_POST['iconColor'])) $this->iconColor = $_POST['iconColor'];
if (isset($_POST['badgeColor'])) $this->badgeColor = $_POST['badgeColor'];
if (isset($_POST['awardAutomatically'])) $this->awardAutomatically = 1;
+ if (isset($_POST['revokeAutomatically']) && $this->awardAutomatically) $this->revokeAutomatically = 1;
if (isset($_POST['trophyUseHtml'])) $this->trophyUseHtml = 1;
if (isset($_POST['showOrder'])) $this->showOrder = intval($_POST['showOrder']);
'type' => $this->type,
'isDisabled' => $this->isDisabled,
'awardAutomatically' => $this->awardAutomatically,
+ 'revokeAutomatically' => $this->revokeAutomatically,
'trophyUseHtml' => $this->trophyUseHtml,
'showOrder' => $this->showOrder
]),
public function reset() {
parent::reset();
- $this->isDisabled = $this->awardAutomatically = $this->categoryID = $this->trophyUseHtml = $this->showOrder = 0;
+ $this->isDisabled = $this->awardAutomatically = $this->categoryID = $this->trophyUseHtml = $this->showOrder = $this->revokeAutomatically = 0;
$this->type = Trophy::TYPE_BADGE;
$this->iconName = $this->uploadedImageURL = '';
$this->iconColor = 'rgba(255, 255, 255, 1)';
'trophyCategories' => TrophyCategoryCache::getInstance()->getCategories(),
'groupedObjectTypes' => $this->conditions,
'awardAutomatically' => $this->awardAutomatically,
+ 'revokeAutomatically' => $this->revokeAutomatically,
'availableTypes' => $this->availableTypes,
'tmpHash' => $this->tmpHash,
'uploadedImageURL' => $this->uploadedImageURL,
$this->iconColor = $this->trophy->iconColor;
$this->badgeColor = $this->trophy->badgeColor;
$this->awardAutomatically = $this->trophy->awardAutomatically;
+ $this->revokeAutomatically = $this->trophy->revokeAutomatically;
$this->trophyUseHtml = $this->trophy->trophyUseHtml;
$this->showOrder = $this->trophy->showOrder;
'type' => $this->type,
'isDisabled' => $this->isDisabled,
'awardAutomatically' => $this->awardAutomatically,
+ 'revokeAutomatically' => $this->revokeAutomatically,
'trophyUseHtml' => $this->trophyUseHtml,
'showOrder' => $this->showOrder
])]);
* @property-read string $badgeColor the icon badge color
* @property-read integer $isDisabled `1` if the trophy is disabled
* @property-read integer $awardAutomatically `1` if the trophy is awarded automatically
- * @property-read integer $trophyUseHtml `1`, if the trophy use a html description
+ * @property-read integer $revokeAutomatically `1` if the trophy is automatically revoked, if the conditions are not longer fulfilled
+ * @property-read integer $trophyUseHtml `1` if the trophy use a html description
* @property-read integer $showOrder position of the trophy in relation to the other trophies at the same location
*/
class Trophy extends DatabaseObject implements ITitledLinkObject, IRouteController {
* @inheritDoc
*/
public function delete() {
+ if (empty($this->objects)) {
+ $this->readObjects();
+ }
+
$trophyIDs = $userIDs = [];
foreach ($this->getObjects() as $object) {
$trophyIDs[] = $object->trophyID;
if (MODULE_TROPHY) {
TrophyConditionHandler::getInstance()->assignTrophies(100);
+ TrophyConditionHandler::getInstance()->revokeTrophies(100);
}
}
}
}
}
+ /**
+ * Revoke user trophies which are not longer fulfills the conditions.
+ *
+ * @param integer $maxRevokes
+ */
+ public function revokeTrophies($maxRevokes = 500) {
+ $trophyList = new TrophyList();
+ $trophyList->getConditionBuilder()->add('awardAutomatically = ?', [1]);
+ $trophyList->getConditionBuilder()->add('revokeAutomatically = ?', [1]);
+ $trophyList->getConditionBuilder()->add('isDisabled = ?', [0]);
+ $trophyList->readObjects();
+
+ $i = 0;
+ foreach ($trophyList as $trophy) {
+ $userTrophyIDs = $this->getRevocableUserTrophyIDs($trophy);
+
+ $i += count($userTrophyIDs);
+
+ (new UserTrophyAction($userTrophyIDs, 'delete'))->executeAction();
+
+ if ($i >= $maxRevokes) return;
+ }
+ }
+
/**
* Returns the users who fulfill all conditions of the given trophy.
*
return $userList->getObjectIDs();
}
+
+ /**
+ * Returns the userTrophyIDs of the users, which no longer fulfills the trophy conditions.
+ *
+ * @param Trophy $trophy
+ * @return integer[]
+ */
+ private function getRevocableUserTrophyIDs(Trophy $trophy) {
+ $pseudoUserList = new UserList();
+ $pseudoUserList->sqlConditionJoins .= " LEFT JOIN wcf".WCF_N."_user_option_value user_option_value ON (user_option_value.userID = user_table.userID)";
+
+ $conditions = $trophy->getConditions();
+ foreach ($conditions as $condition) {
+ $condition->getObjectType()->getProcessor()->addUserCondition($condition, $pseudoUserList);
+ }
+
+ $userList = new UserList();
+ $userList->sqlConditionJoins = $pseudoUserList->sqlConditionJoins;
+ $userList->sqlOrderBy = $pseudoUserList->sqlOrderBy;
+ $userList->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_trophy user_trophy ON (user_table.userID = user_trophy.userID)";
+ $userList->useQualifiedShorthand = false;
+ $userList->sqlSelects = "user_trophy.userTrophyID, user_table.userID";
+ $pseudoUserList->getConditionBuilder()->enableWhereKeyword(false);
+ $userList->getConditionBuilder()->add('NOT('. $pseudoUserList->getConditionBuilder() .')', $pseudoUserList->getConditionBuilder()->getParameters());
+ $userList->getConditionBuilder()->add('user_table.userID IN (SELECT userID FROM wcf'.WCF_N.'_user_trophy WHERE trophyID IN (?))', [$trophy->trophyID]);
+ $userList->readObjects();
+
+ return array_map(function($object) {
+ return $object->userTrophyID;
+ }, $userList->getObjects());
+ }
}
<item name="wcf.acp.trophy.category"><![CDATA[Kategorie]]></item>
<item name="wcf.acp.trophy.isDisabled"><![CDATA[Trophäe deaktivieren]]></item>
<item name="wcf.acp.trophy.awardAutomatically"><![CDATA[Trophäe automatisch vergeben]]></item>
+ <item name="wcf.acp.trophy.revokeAutomatically"><![CDATA[Trophäe automatisch entziehen, wenn die Bedingungen nicht mehr erfüllt sind]]></item>
<item name="wcf.acp.trophy.type"><![CDATA[Trophäen-Typ]]></item>
<item name="wcf.acp.trophy.type.badge"><![CDATA[Badge]]></item>
<item name="wcf.acp.trophy.type.imageUpload"><![CDATA[Bild-Datei]]></item>
<item name="wcf.acp.trophy.category"><![CDATA[Category]]></item>
<item name="wcf.acp.trophy.isDisabled"><![CDATA[Disable Trophy]]></item>
<item name="wcf.acp.trophy.awardAutomatically"><![CDATA[Award trophy automatically]]></item>
+ <item name="wcf.acp.trophy.revokeAutomatically"><![CDATA[Revoke trophy automatically if the conditions are not longer fulfilled]]></item>
<item name="wcf.acp.trophy.type"><![CDATA[Trophy Type]]></item>
<item name="wcf.acp.trophy.type.badge"><![CDATA[Badge]]></item>
<item name="wcf.acp.trophy.type.imageUpload"><![CDATA[Image]]></item>
badgeColor VARCHAR(255),
isDisabled TINYINT(1) NOT NULL DEFAULT 0,
awardAutomatically TINYINT(1) NOT NULL DEFAULT 0,
+ revokeAutomatically TINYINT(1) NOT NULL DEFAULT 0,
trophyUseHtml TINYINT(1) NOT NULL DEFAULT 0,
showOrder INT(10) NOT NULL DEFAULT 0,
KEY(categoryID)