From: Marcel Werk Date: Mon, 20 May 2013 22:44:50 +0000 (+0200) Subject: Merged com.woltlab.wcf.label into WCF X-Git-Tag: 2.0.0_Beta_1~121 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=3b75466f36ebaa22b1ec379cdedf8b4c50ef0ed5;p=GitHub%2FWoltLab%2FWCF.git Merged com.woltlab.wcf.label into WCF --- diff --git a/com.woltlab.wcf/aclOption.xml b/com.woltlab.wcf/aclOption.xml new file mode 100644 index 0000000000..a608f243f6 --- /dev/null +++ b/com.woltlab.wcf/aclOption.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/com.woltlab.wcf/acpMenu.xml b/com.woltlab.wcf/acpMenu.xml index e20f71dfd4..2f042a83f9 100644 --- a/com.woltlab.wcf/acpMenu.xml +++ b/com.woltlab.wcf/acpMenu.xml @@ -490,6 +490,38 @@ admin.content.dashboard.canEditDashboard + + wcf.acp.menu.link.content + + + + + wcf.acp.menu.link.label + admin.content.label.canManageLabel + 1 + + + + + wcf.acp.menu.link.label + admin.content.label.canManageLabel + 2 + + + + + wcf.acp.menu.link.label + admin.content.label.canManageLabel + 3 + + + + + wcf.acp.menu.link.label + admin.content.label.canManageLabel + 4 + + 5 diff --git a/com.woltlab.wcf/objectType.xml b/com.woltlab.wcf/objectType.xml index 785418ca82..7d9b6e1330 100644 --- a/com.woltlab.wcf/objectType.xml +++ b/com.woltlab.wcf/objectType.xml @@ -205,5 +205,10 @@ wcf\system\moderation\queue\report\CommentResponseModerationQueueReportHandler + + + com.woltlab.wcf.label + com.woltlab.wcf.acl + \ No newline at end of file diff --git a/com.woltlab.wcf/objectTypeDefinition.xml b/com.woltlab.wcf/objectTypeDefinition.xml index f836db6673..5498a02015 100644 --- a/com.woltlab.wcf/objectTypeDefinition.xml +++ b/com.woltlab.wcf/objectTypeDefinition.xml @@ -99,5 +99,15 @@ com.woltlab.wcf.comment.commentableContent wcf\system\comment\manager\ICommentManager + + + com.woltlab.wcf.label.object + wcf\system\label\object\ILabelObjectHandler + + + + com.woltlab.wcf.label.objectType + wcf\system\label\object\type\ILabelObjectTypeHandler + diff --git a/com.woltlab.wcf/package.xml b/com.woltlab.wcf/package.xml index e8f0bca26d..90a5376580 100644 --- a/com.woltlab.wcf/package.xml +++ b/com.woltlab.wcf/package.xml @@ -38,6 +38,7 @@ userProfileMenu.xml userMenu.xml userNotificationEvent.xml + aclOption.xml diff --git a/com.woltlab.wcf/userGroupOption.xml b/com.woltlab.wcf/userGroupOption.xml index dc89504aa2..9fb1123cfb 100644 --- a/com.woltlab.wcf/userGroupOption.xml +++ b/com.woltlab.wcf/userGroupOption.xml @@ -92,6 +92,9 @@ admin.content + + admin.content + admin @@ -535,6 +538,13 @@ png]]> 1 + + diff --git a/wcfsetup/install/files/acp/templates/labelAdd.tpl b/wcfsetup/install/files/acp/templates/labelAdd.tpl new file mode 100644 index 0000000000..5929108ee8 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/labelAdd.tpl @@ -0,0 +1,122 @@ +{include file='header'} + + + +
+

{lang}wcf.acp.label.{$action}{/lang}

+
+ +{if $errorField} +

{lang}wcf.global.form.error{/lang}

+{/if} + +{if $success|isset} +

{lang}wcf.global.success.{$action}{/lang}

+{/if} + +
+ +
+ +{if $labelGroupList|count} +
+
+
+ {lang}wcf.global.form.data{/lang} + + +
+
+ + {if $errorField == 'groupID'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {else} + {lang}wcf.acp.label.group.error.{@$errorType}{/lang} + {/if} + + {/if} +
+ + + +
+
+ + {if $errorField == 'label'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {elseif $errorType == 'multilingual'} + {lang}wcf.global.form.error.multilingual{/lang} + {else} + {lang}wcf.acp.label.label.error.{@$errorType}{/lang} + {/if} + + {/if} +
+ + {include file='multipleLanguageInputJavascript' elementIdentifier='label' forceSelection=false} + + +
+
+
    + {foreach from=$availableCssClassNames item=className} + {if $className == 'custom'} +
  • + {else} +
  • + {/if} + {/foreach} +
+ + {if $errorField == 'cssClassName'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {else} + {lang}wcf.acp.label.cssClassName.error.{@$errorType}{/lang} + {/if} + + {/if} +
+ + + {event name='dataFields'} +
+ + {event name='fieldsets'} +
+ +
+ +
+
+{else} +

{lang}wcf.acp.label.error.noGroups{/lang}

+{/if} + +{include file='footer'} diff --git a/wcfsetup/install/files/acp/templates/labelGroupAdd.tpl b/wcfsetup/install/files/acp/templates/labelGroupAdd.tpl new file mode 100644 index 0000000000..2e86afabdc --- /dev/null +++ b/wcfsetup/install/files/acp/templates/labelGroupAdd.tpl @@ -0,0 +1,117 @@ +{include file='header'} + +{include file='aclPermissions'} + + + +
+

{lang}wcf.acp.label.group.{$action}{/lang}

+
+ +{if $errorField} +

{lang}wcf.global.form.error{/lang}

+{/if} + +{if $success|isset} +

{lang}wcf.global.success.{$action}{/lang}

+{/if} + +
+ +
+ +
+
+ + +
+
+ {lang}wcf.global.form.data{/lang} + + +
+
+ + {if $errorField == 'groupName'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {else} + {lang}wcf.acp.label.group.groupName.error.{@$errorType}{/lang} + {/if} + + {/if} +
+ + +
+
+
+
+ +
+
{lang}wcf.acl.permissions{/lang}
+
+
+ + {event name='dataFields'} +
+ + {event name='generalFieldsets'} +
+ +
+
+ {lang}wcf.acp.label.group.category.connect{/lang} + + {foreach from=$labelObjectTypeContainers item=container} + {if $container->isBooleanOption()} + + {else} +
+
objectTypeID = {@$container->getObjectTypeID()}
+
+
    + {foreach from=$container item=objectType} +
  • getDepth()} style="padding-left: {21 * $objectType->getDepth()}px"{/if} data-depth="{@$objectType->getDepth()}"> + {$objectType->getLabel()} + +
  • + {/foreach} +
+
+
+ {/if} + {/foreach} +
+ + {event name='connectFieldsets'} +
+
+ +
+ +
+
+ +{include file='footer'} diff --git a/wcfsetup/install/files/acp/templates/labelGroupList.tpl b/wcfsetup/install/files/acp/templates/labelGroupList.tpl new file mode 100644 index 0000000000..132def0590 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/labelGroupList.tpl @@ -0,0 +1,93 @@ +{include file='header'} + + + +
+

{lang}wcf.acp.label.group.list{/lang}

+
+ +
+ {pages print=true assign=pagesLinks controller="LabelGroupList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"} + + +
+ +{if $objects|count} +
+
+

{lang}wcf.acp.label.group.list{/lang} {#$items}

+
+ + + + + + + + {event name='columnHeads'} + + + + + {foreach from=$objects item=group} + + + + + + {event name='columns'} + + {/foreach} + +
{lang}wcf.global.objectID{/lang}{lang}wcf.acp.label.group.groupName{/lang}
+ {if $group->isEditable()} + + {/if} + {if $group->isDeletable()} + + {/if} + + {event name='rowButtons'} + {@$group->groupID}{if $group->isEditable()}

{$group->groupName}{else}{$group->groupName}

{/if}
+
+ +
+ {@$pagesLinks} + + +
+{else} +

{lang}wcf.acp.label.group.noneAvailable{/lang}

+{/if} + +{include file='footer'} diff --git a/wcfsetup/install/files/acp/templates/labelList.tpl b/wcfsetup/install/files/acp/templates/labelList.tpl new file mode 100644 index 0000000000..3663f89f82 --- /dev/null +++ b/wcfsetup/install/files/acp/templates/labelList.tpl @@ -0,0 +1,95 @@ +{include file='header'} + + + +
+

{lang}wcf.acp.label.list{/lang}

+
+ +
+ {pages print=true assign=pagesLinks controller="LabelList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"} + + +
+ +{if $objects|count} +
+
+

{lang}wcf.acp.label.list{/lang} {#$items}

+
+ + + + + + + + + {event name='columnHeads'} + + + + + {foreach from=$objects item=label} + + + + + + + {event name='columns'} + + {/foreach} + +
{lang}wcf.global.objectID{/lang}{lang}wcf.acp.label.label{/lang}{lang}wcf.acp.label.group.groupName{/lang}
+ {if $label->isEditable()} + + {/if} + {if $label->isDeletable()} + + {/if} + + {event name='rowButtons'} + {@$label->labelID}{if $label->isEditable()}{$label}

{else}

{$label}{/if}

{$label->groupName}
+
+ +
+ {@$pagesLinks} + + +
+{else} +

{lang}wcf.acp.label.noneAvailable{/lang}

+{/if} + +{include file='footer'} diff --git a/wcfsetup/install/files/js/WCF.Label.js b/wcfsetup/install/files/js/WCF.Label.js new file mode 100644 index 0000000000..23d3eb39a2 --- /dev/null +++ b/wcfsetup/install/files/js/WCF.Label.js @@ -0,0 +1,259 @@ +/** + * Namespace for labels. + */ +WCF.Label = {}; + +/** + * Provides enhancements for ACP label management. + */ +WCF.Label.ACPList = Class.extend({ + /** + * input element + * @var jQuery + */ + _labelInput: null, + + /** + * list of pre-defined label items + * @var array + */ + _labelList: [ ], + + /** + * Intitializes the ACP label list. + */ + init: function() { + this._labelInput = $('#label').keydown($.proxy(this._keyPressed, this)).keyup($.proxy(this._keyPressed, this)).blur($.proxy(this._keyPressed, this)); + + $('#labelList').find('input[type="radio"]').each($.proxy(function(index, input) { + var $input = $(input); + + // ignore custom values + if ($input.prop('value') !== 'custom') { + this._labelList.push($($input.next('span'))); + } + }, this)); + }, + + /** + * Renders label name as label or falls back to a default value if label is empty. + */ + _keyPressed: function() { + var $text = this._labelInput.prop('value'); + if ($text === '') $text = WCF.Language.get('wcf.acp.label.defaultValue'); + + for (var $i = 0, $length = this._labelList.length; $i < $length; $i++) { + this._labelList[$i].text($text); + } + } +}); + +/** + * Provides simple logic to inherit associations within structured lists. + */ +WCF.Label.ACPList.Connect = Class.extend({ + /** + * Initializes inheritation for structured lists. + */ + init: function() { + var $listItems = $('#connect .structuredList li'); + if (!$listItems.length) return; + + $listItems.each($.proxy(function(index, item) { + $(item).find('input[type="checkbox"]').click($.proxy(this._click, this)); + }, this)); + }, + + /** + * Marks items as checked if they're logically below current item. + * + * @param object event + */ + _click: function(event) { + var $listItem = $(event.currentTarget); + if ($listItem.is(':checked')) { + $listItem = $listItem.parents('li'); + var $depth = $listItem.data('depth'); + + while (true) { + $listItem = $listItem.next(); + if (!$listItem.length) { + // no more siblings + return true; + } + + // element is on the same or higher level (= lower depth) + if ($listItem.data('depth') <= $depth) { + return true; + } + + $listItem.find('input[type="checkbox"]').prop('checked', 'checked'); + } + } + } +}); + +/** + * Provides a flexible label chooser. + * + * @param object selectedLabelIDs + * @param string containerSelector + * @param string submitButtonSelector + * @param boolean showWithoutSelection + */ +WCF.Label.Chooser = Class.extend({ + /** + * label container + * @var jQuery + */ + _container: null, + + /** + * list of label groups + * @var object + */ + _groups: { }, + + /** + * show the 'without selection' option + * @var boolean + */ + _showWithoutSelection: false, + + /** + * Initializes a new label chooser. + * + * @param object selectedLabelIDs + * @param string containerSelector + * @param string submitButtonSelector + * @param boolean showWithoutSelection + */ + init: function(selectedLabelIDs, containerSelector, submitButtonSelector, showWithoutSelection) { + this._container = null; + this._groups = { }; + this._showWithoutSelection = (showWithoutSelection === true); + + // init containers + this._initContainers(containerSelector); + + // pre-select labels + if ($.getLength(selectedLabelIDs)) { + for (var $groupID in selectedLabelIDs) { + this._groups[$groupID].find('.dropdownMenu > li').each($.proxy(function(index, label) { + var $label = $(label); + var $labelID = $label.data('labelID') || 0; + if ($labelID && selectedLabelIDs[$groupID] == $labelID) { + this._selectLabel($label, true); + } + }, this)); + } + } + + // mark all containers as initialized + for (var $containerID in this._containers) { + var $dropdown = this._containers[$containerID]; + if ($dropdown.data('labelID') === undefined) { + $dropdown.data('labelID', 0); + } + } + + this._container = $(containerSelector); + if (submitButtonSelector) { + $(submitButtonSelector).click($.proxy(this._submit, this)); + } + else if (this._container.is('form')) { + this._container.submit($.proxy(this._submit, this)); + } + }, + + /** + * Initializes label groups. + * + * @param string containerSelector + */ + _initContainers: function(containerSelector) { + $(containerSelector).find('.labelChooser').each($.proxy(function(index, group) { + var $group = $(group); + var $groupID = $group.data('groupID'); + + if (!this._groups[$groupID]) { + this._groups[$groupID] = $group; + var $dropdownMenu = $group.find('.dropdownMenu'); + $dropdownMenu.find('li').click($.proxy(this._click, this)); + + if (!$group.data('forceSelection') || this._showWithoutSelection) { + $('
  • ' + WCF.Language.get('wcf.label.withoutSelection') + '
  • ').appendTo($dropdownMenu).click($.proxy(this._click, this)); + } + + if (!$group.data('forceSelection')) { + var $buttonEmpty = $('
  • ' + WCF.Language.get('wcf.label.none') + '
  • ').appendTo($dropdownMenu); + $buttonEmpty.click($.proxy(this._click, this)); + } + } + }, this)); + }, + + /** + * Handles label selections. + * + * @param object event + */ + _click: function(event) { + this._selectLabel($(event.currentTarget), false); + }, + + /** + * Selects a label. + * + * @param jQuery label + * @param boolean onInit + */ + _selectLabel: function(label, onInit) { + var $group = label.parents('.dropdown'); + + // already initialized, ignore + if (onInit && $group.data('labelID') !== undefined) { + return; + } + + // save label id + if (label.data('labelID')) { + $group.data('labelID', label.data('labelID')); + } + else { + $group.data('labelID', 0); + } + + // replace button + label = label.find('span > span'); + $group.find('.dropdownToggle > span').removeClass().addClass(label.attr('class')).text(label.text()); + }, + + /** + * Creates hidden input elements on submit. + */ + _submit: function() { + // get form submit area + var $formSubmit = this._container.find('.formSubmit'); + + // remove old, hidden values + $formSubmit.find('input[type="hidden"]').each(function(index, input) { + var $input = $(input); + if ($input.attr('name').indexOf('labelIDs[') === 0) { + $input.remove(); + } + }); + + // insert label ids + for (var $groupID in this._groups) { + var $group = this._groups[$groupID]; + if ($group.data('labelID')) { + $('').appendTo($formSubmit); + } + } + } +}); \ No newline at end of file diff --git a/wcfsetup/install/files/js/WCF.Label.min.js b/wcfsetup/install/files/js/WCF.Label.min.js new file mode 100644 index 0000000000..c9bab186a9 --- /dev/null +++ b/wcfsetup/install/files/js/WCF.Label.min.js @@ -0,0 +1 @@ +WCF.Label={};WCF.Label.ACPList=Class.extend({_labelInput:null,_labelList:[],init:function(){this._labelInput=$("#label").keydown($.proxy(this._keyPressed,this)).keyup($.proxy(this._keyPressed,this)).blur($.proxy(this._keyPressed,this));$("#labelList").find('input[type="radio"]').each($.proxy(function(b,a){var c=$(a);if(c.prop("value")!=="custom"){this._labelList.push($(c.next("span")))}},this))},_keyPressed:function(){var a=this._labelInput.prop("value");if(a===""){a=WCF.Language.get("wcf.acp.label.defaultValue")}for(var c=0,b=this._labelList.length;c li").each($.proxy(function(j,i){var h=$(i);var k=h.data("labelID")||0;if(k&&e[a]==k){this._selectLabel(h,true)}},this))}}for(var c in this._containers){var f=this._containers[c];if(f.data("labelID")===undefined){f.data("labelID",0)}}this._container=$(b);if(d){$(d).click($.proxy(this._submit,this))}else{if(this._container.is("form")){this._container.submit($.proxy(this._submit,this))}}},_initContainers:function(a){$(a).find(".labelChooser").each($.proxy(function(d,g){var e=$(g);var b=e.data("groupID");if(!this._groups[b]){this._groups[b]=e;var c=e.find(".dropdownMenu");c.find("li").click($.proxy(this._click,this));if(!e.data("forceSelection")||this._showWithoutSelection){$('
  • '+WCF.Language.get("wcf.label.withoutSelection")+"
  • ").appendTo(c).click($.proxy(this._click,this))}if(!e.data("forceSelection")){var f=$('
  • '+WCF.Language.get("wcf.label.none")+"
  • ").appendTo(c);f.click($.proxy(this._click,this))}}},this))},_click:function(a){this._selectLabel($(a.currentTarget),false)},_selectLabel:function(a,c){var b=a.parents(".dropdown");if(c&&b.data("labelID")!==undefined){return}if(a.data("labelID")){b.data("labelID",a.data("labelID"))}else{b.data("labelID",0)}a=a.find("span > span");b.find(".dropdownToggle > span").removeClass().addClass(a.attr("class")).text(a.text())},_submit:function(){var b=this._container.find(".formSubmit");b.find('input[type="hidden"]').each(function(e,d){var f=$(d);if(f.attr("name").indexOf("labelIDs[")===0){f.remove()}});for(var a in this._groups){var c=this._groups[a];if(c.data("labelID")){$('').appendTo(b)}}}}); \ No newline at end of file diff --git a/wcfsetup/install/files/lib/acp/form/LabelAddForm.class.php b/wcfsetup/install/files/lib/acp/form/LabelAddForm.class.php new file mode 100644 index 0000000000..feee0636a5 --- /dev/null +++ b/wcfsetup/install/files/lib/acp/form/LabelAddForm.class.php @@ -0,0 +1,213 @@ + + * @package com.woltlab.wcf.label + * @subpackage acp.form + * @category Community Framework + */ +class LabelAddForm extends AbstractForm { + /** + * @see wcf\page\AbstractPage::$activeMenuItem + */ + public $activeMenuItem = 'wcf.acp.menu.link.label.add'; + + /** + * @see wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array('admin.content.label.canManageLabel'); + + /** + * label group id + * @var integer + */ + public $groupID = 0; + + /** + * label value + * @var string + */ + public $label = ''; + + /** + * label group list object + * @var wcf\data\label\group\LabelGroupList + */ + public $labelGroupList = null; + + /** + * CSS class name + * @var string + */ + public $cssClassName = ''; + + /** + * custom CSS class name + * @var string + */ + public $customCssClassName = ''; + + /** + * list of pre-defined css class names + * @var array + */ + public $availableCssClassNames = array( + 'yellow', + 'orange', + 'brown', + 'red', + 'pink', + 'purple', + 'blue', + 'green', + 'black', + + 'none', /* not a real value */ + 'custom' /* not a real value */ + ); + + /** + * @see wcf\page\IPage::readParameters() + */ + public function readParameters() { + parent::readParameters(); + + I18nHandler::getInstance()->register('label'); + } + + /** + * @see wcf\form\IForm::readFormParameters() + */ + public function readFormParameters() { + parent::readFormParameters(); + + I18nHandler::getInstance()->readValues(); + + if (I18nHandler::getInstance()->isPlainValue('label')) $this->label = I18nHandler::getInstance()->getValue('label'); + if (isset($_POST['cssClassName'])) $this->cssClassName = StringUtil::trim($_POST['cssClassName']); + if (isset($_POST['customCssClassName'])) $this->customCssClassName = StringUtil::trim($_POST['customCssClassName']); + if (isset($_POST['groupID'])) $this->groupID = intval($_POST['groupID']); + } + + /** + * @see wcf\form\IForm::validate() + */ + public function validate() { + parent::validate(); + + // validate label + if (!I18nHandler::getInstance()->validateValue('label')) { + if (I18nHandler::getInstance()->isPlainValue('label')) { + throw new UserInputException('label'); + } + else { + throw new UserInputException('label', 'multilingual'); + } + } + + // validate group + if (!$this->groupID) { + throw new UserInputException('groupID'); + } + $groups = $this->labelGroupList->getObjects(); + if (!isset($groups[$this->groupID])) { + throw new UserInputException('groupID', 'invalid'); + } + + if (empty($this->cssClassName)) { + throw new UserInputException('cssClassName', 'empty'); + } + else if (!in_array($this->cssClassName, $this->availableCssClassNames)) { + throw new UserInputException('cssClassName', 'notValid'); + } + else if ($this->cssClassName == 'custom') { + if (!empty($this->customCssClassName) && !Regex::compile('^-?[_a-zA-Z]+[_a-zA-Z0-9-]+$')->match($this->customCssClassName)) { + throw new UserInputException('cssClassName', 'notValid'); + } + } + } + + /** + * @see wcf\form\IForm::save() + */ + public function save() { + parent::save(); + + // save label + $this->objectAction = new LabelAction(array(), 'create', array('data' => array( + 'label' => $this->label, + 'cssClassName' => ($this->cssClassName == 'custom' ? $this->customCssClassName : $this->cssClassName), + 'groupID' => $this->groupID + ))); + $this->objectAction->executeAction(); + + if (!I18nHandler::getInstance()->isPlainValue('label')) { + $returnValues = $this->objectAction->getReturnValues(); + $labelID = $returnValues['returnValues']->labelID; + I18nHandler::getInstance()->save('label', 'wcf.acp.label.label'.$labelID, 'wcf.acp.label', PackageCache::getInstance()->getPackageID('com.woltlab.wcf.label')); + + // update group name + $labelEditor = new LabelEditor($returnValues['returnValues']); + $labelEditor->update(array( + 'label' => 'wcf.acp.label.label'.$labelID + )); + } + + $this->saved(); + + // reset values + $this->label = $this->cssClassName = $this->customCssClassName = ''; + $this->groupID = 0; + + I18nHandler::getInstance()->reset(); + + // show success + WCF::getTPL()->assign(array( + 'success' => true + )); + } + + /** + * @see wcf\page\IPage::readData() + */ + public function readData() { + $this->labelGroupList = new LabelGroupList(); + $this->labelGroupList->readObjects(); + + parent::readData(); + } + + /** + * @see wcf\page\IPage::assignVariables() + */ + public function assignVariables() { + parent::assignVariables(); + + I18nHandler::getInstance()->assignVariables(); + + WCF::getTPL()->assign(array( + 'action' => 'add', + 'availableCssClassNames' => $this->availableCssClassNames, + 'cssClassName' => $this->cssClassName, + 'customCssClassName' => $this->customCssClassName, + 'groupID' => $this->groupID, + 'label' => $this->label, + 'labelGroupList' => $this->labelGroupList + )); + } +} diff --git a/wcfsetup/install/files/lib/acp/form/LabelEditForm.class.php b/wcfsetup/install/files/lib/acp/form/LabelEditForm.class.php new file mode 100644 index 0000000000..9509def5b7 --- /dev/null +++ b/wcfsetup/install/files/lib/acp/form/LabelEditForm.class.php @@ -0,0 +1,124 @@ + + * @package com.woltlab.wcf.label + * @subpackage acp.form + * @category Community Framework + */ +class LabelEditForm extends LabelAddForm { + /** + * @see wcf\page\AbstractPage::$activeMenuItem + */ + public $activeMenuItem = 'wcf.acp.menu.link.label'; + + /** + * @see wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array('admin.content.label.canManageLabel'); + + /** + * label id + * @var integer + */ + public $labelID = 0; + + /** + * label object + * @var wcf\data\label\Label + */ + public $labelObj = null; + + /** + * @see wcf\page\IPage::readParameters() + */ + public function readParameters() { + parent::readParameters(); + + if (isset($_REQUEST['id'])) $this->labelID = intval($_REQUEST['id']); + $this->labelObj = new Label($this->labelID); + if (!$this->labelObj->labelID) { + throw new IllegalLinkException(); + } + } + + /** + * @see wcf\form\IForm::save() + */ + public function save() { + AbstractForm::save(); + + $this->label = 'wcf.acp.label.label'.$this->labelObj->labelID; + if (I18nHandler::getInstance()->isPlainValue('label')) { + I18nHandler::getInstance()->remove($this->label, PackageCache::getInstance()->getPackageID('com.woltlab.wcf.label')); + $this->label = I18nHandler::getInstance()->getValue('label'); + } + else { + I18nHandler::getInstance()->save('label', $this->label, 'wcf.acp.label', PackageCache::getInstance()->getPackageID('com.woltlab.wcf.label')); + } + + // update label + $this->objectAction = new LabelAction(array($this->labelID), 'update', array('data' => array( + 'label' => $this->label, + 'cssClassName' => ($this->cssClassName == 'custom' ? $this->customCssClassName : $this->cssClassName), + 'groupID' => $this->groupID + ))); + $this->objectAction->executeAction(); + + $this->saved(); + + // reset values if non-custom value was choosen + if ($this->cssClassName != 'custom') $this->customCssClassName = ''; + + // show success + WCF::getTPL()->assign(array( + 'success' => true + )); + } + + /** + * @see wcf\page\IPage::readData() + */ + public function readData() { + parent::readData(); + + if (empty($_POST)) { + I18nHandler::getInstance()->setOptions('label', PackageCache::getInstance()->getPackageID('com.woltlab.wcf.label'), $this->labelObj->label, 'wcf.acp.label.label\d+'); + $this->label = $this->labelObj->label; + + $this->cssClassName = $this->labelObj->cssClassName; + if (!in_array($this->cssClassName, $this->availableCssClassNames)) { + $this->customCssClassName = $this->cssClassName; + $this->cssClassName = 'custom'; + } + + $this->groupID = $this->labelObj->groupID; + } + } + + /** + * @see wcf\page\IPage::assignVariables() + */ + public function assignVariables() { + parent::assignVariables(); + + I18nHandler::getInstance()->assignVariables(!empty($_POST)); + + WCF::getTPL()->assign(array( + 'label' => $this->labelObj, + 'action' => 'edit' + )); + } +} diff --git a/wcfsetup/install/files/lib/acp/form/LabelGroupAddForm.class.php b/wcfsetup/install/files/lib/acp/form/LabelGroupAddForm.class.php new file mode 100644 index 0000000000..3f615f7599 --- /dev/null +++ b/wcfsetup/install/files/lib/acp/form/LabelGroupAddForm.class.php @@ -0,0 +1,250 @@ + + * @package com.woltlab.wcf.label + * @subpackage acp.form + * @category Community Framework + */ +class LabelGroupAddForm extends AbstractForm { + /** + * @see wcf\page\AbstractPage::$activeMenuItem + */ + public $activeMenuItem = 'wcf.acp.menu.link.label.group.add'; + + /** + * @see wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array('admin.content.label.canManageLabel'); + + /** + * force users to select a label + * @var boolean + */ + public $forceSelection = false; + + /** + * group name + * @var string + */ + public $groupName = ''; + + /** + * list of label object type handlers + * @var array + */ + public $labelObjectTypes = array(); + + /** + * list of label object type containers + * @var array + */ + public $labelObjectTypeContainers = array(); + + /** + * list of label group to object type relations + * @var array + */ + public $objectTypes = array(); + + /** + * object type id + * @var integer + */ + public $objectTypeID = 0; + + /** + * @see wcf\page\AbstractPage::readParameters() + */ + public function readParameters() { + parent::readParameters(); + + $this->objectTypeID = ACLHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.label'); + } + + /** + * @see wcf\form\IForm::readFormParameters() + */ + public function readFormParameters() { + parent::readFormParameters(); + + if (isset($_POST['forceSelection'])) $this->forceSelection = true; + if (isset($_POST['groupName'])) $this->groupName = StringUtil::trim($_POST['groupName']); + if (isset($_POST['objectTypes']) && is_array($_POST['objectTypes'])) $this->objectTypes = $_POST['objectTypes']; + } + + /** + * @see wcf\page\IPage::readData() + */ + public function readData() { + // get label object type handlers + $objectTypes = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.label.objectType'); + foreach ($objectTypes as $objectType) { + $this->labelObjectTypes[$objectType->objectTypeID] = $objectType->getProcessor(); + $this->labelObjectTypes[$objectType->objectTypeID]->setObjectTypeID($objectType->objectTypeID); + } + + foreach ($this->labelObjectTypes as $objectTypeID => $labelObjectType) { + $this->labelObjectTypeContainers[$objectTypeID] = $labelObjectType->getContainer(); + } + + parent::readData(); + + // assign new values for object relations + $this->setObjectTypeRelations(); + } + + /** + * @see wcf\form\IForm::validate() + */ + public function validate() { + parent::validate(); + + // validate class name + if (empty($this->groupName)) { + throw new UserInputException('groupName'); + } + + // validate object type relations + foreach ($this->objectTypes as $objectTypeID => $data) { + if (!isset($this->labelObjectTypes[$objectTypeID])) { + unset($this->objectTypes[$objectTypeID]); + } + } + } + + /** + * @see wcf\form\IForm::save() + */ + public function save() { + parent::save(); + + // save label + $this->objectAction = new LabelGroupAction(array(), 'create', array('data' => array( + 'forceSelection' => ($this->forceSelection ? 1 : 0), + 'groupName' => $this->groupName + ))); + $returnValues = $this->objectAction->executeAction(); + + // save acl + ACLHandler::getInstance()->save($returnValues['returnValues']->groupID, $this->objectTypeID); + + // save object type relations + $this->saveObjectTypeRelations($returnValues['returnValues']->groupID); + + $this->saved(); + + // reset values + $this->forceSelection = false; + $this->groupName = ''; + $this->objectTypes = array(); + $this->setObjectTypeRelations(); + + // show success + WCF::getTPL()->assign(array( + 'success' => true + )); + } + + /** + * @see wcf\page\IPage::assignVariables() + */ + public function assignVariables() { + parent::assignVariables(); + + WCF::getTPL()->assign(array( + 'action' => 'add', + 'forceSelection' => $this->forceSelection, + 'groupName' => $this->groupName, + 'labelObjectTypeContainers' => $this->labelObjectTypeContainers, + 'objectTypeID' => $this->objectTypeID + )); + } + + /** + * Saves label group to object relations. + * + * @param integer $groupID + */ + protected function saveObjectTypeRelations($groupID) { + WCF::getDB()->beginTransaction(); + + // remove old relations + if ($groupID !== null) { + $sql = "DELETE FROM wcf".WCF_N."_label_group_to_object + WHERE groupID = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array($groupID)); + } + + // insert new relations + if (!empty($this->objectTypes)) { + $sql = "INSERT INTO wcf".WCF_N."_label_group_to_object + (groupID, objectTypeID, objectID) + VALUES (?, ?, ?)"; + $statement = WCF::getDB()->prepareStatement($sql); + + foreach ($this->objectTypes as $objectTypeID => $data) { + foreach ($data as $objectID) { + // use "0" (stored as NULL) for simple true/false states + if (!$objectID) $objectID = null; + + $statement->execute(array( + $groupID, + $objectTypeID, + $objectID + )); + } + } + } + + WCF::getDB()->commitTransaction(); + } + + /** + * Sets object type relations. + */ + protected function setObjectTypeRelations($data = null) { + if (!empty($_POST)) { + // use POST data + $data = &$this->objectTypes; + } + + // no data provided and no POST data exists + if ($data === null || !is_array($data)) { + // nothing to do here + return; + } + + foreach ($this->labelObjectTypeContainers as $objectTypeID => $container) { + if ($container->isBooleanOption()) { + $optionValue = (isset($data[$objectTypeID])) ? 1 : 0; + $container->setOptionValue($optionValue); + } + else { + $hasData = (isset($data[$objectTypeID])); + foreach ($container as $object) { + if (!$hasData) { + $object->setOptionValue(0); + } + else { + $optionValue = (in_array($object->getObjectID(), $data[$objectTypeID])) ? 1 : 0; + $object->setOptionValue($optionValue); + } + } + } + } + } +} diff --git a/wcfsetup/install/files/lib/acp/form/LabelGroupEditForm.class.php b/wcfsetup/install/files/lib/acp/form/LabelGroupEditForm.class.php new file mode 100644 index 0000000000..96f95a1df2 --- /dev/null +++ b/wcfsetup/install/files/lib/acp/form/LabelGroupEditForm.class.php @@ -0,0 +1,133 @@ + + * @package com.woltlab.wcf.label + * @subpackage acp.form + * @category Community Framework + */ +class LabelGroupEditForm extends LabelGroupAddForm { + /** + * @see wcf\page\AbstractPage::$activeMenuItem + */ + public $activeMenuItem = 'wcf.acp.menu.link.label'; + + /** + * @see wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array('admin.content.label.canManageLabel'); + + /** + * group id + * @var integer + */ + public $groupID = 0; + + /** + * label group object + * @var wcf\data\label\group\LabelGroup + */ + public $group = null; + + /** + * @see wcf\page\IPage::readParameters() + */ + public function readParameters() { + parent::readParameters(); + + if (isset($_REQUEST['id'])) $this->groupID = intval($_REQUEST['id']); + $this->group = new LabelGroup($this->groupID); + if (!$this->group->groupID) { + throw new IllegalLinkException(); + } + } + + /** + * @see wcf\form\IForm::save() + */ + public function save() { + AbstractForm::save(); + + // update label + $this->objectAction = new LabelGroupAction(array($this->groupID), 'update', array('data' => array( + 'forceSelection' => ($this->forceSelection ? 1 : 0), + 'groupName' => $this->groupName + ))); + $this->objectAction->executeAction(); + + // update acl + ACLHandler::getInstance()->save($this->groupID, $this->objectTypeID); + + // update object type relations + $this->saveObjectTypeRelations($this->groupID); + + $this->saved(); + + // show success + WCF::getTPL()->assign(array( + 'success' => true + )); + } + + /** + * @see wcf\page\IPage::readData() + */ + public function readData() { + parent::readData(); + + if (empty($_POST)) { + $this->forceSelection = ($this->group->forceSelection ? true : false); + $this->groupName = $this->group->groupName; + } + } + + /** + * @see wcf\page\IPage::assignVariables() + */ + public function assignVariables() { + parent::assignVariables(); + + WCF::getTPL()->assign(array( + 'action' => 'edit', + 'groupID' => $this->groupID, + 'labelGroup' => $this->group + )); + } + + /** + * @see wcf\acp\form\LabelGroupAddForm::setObjectTypeRelations() + */ + protected function setObjectTypeRelations($data = null) { + if (empty($_POST)) { + // read database values + $sql = "SELECT objectTypeID, objectID + FROM wcf".WCF_N."_label_group_to_object + WHERE groupID = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array($this->groupID)); + + $data = array(); + while ($row = $statement->fetchArray()) { + if (!isset($data[$row['objectTypeID']])) { + $data[$row['objectTypeID']] = array(); + } + + // prevent NULL values which confuse isset() + $data[$row['objectTypeID']][] = ($row['objectID']) ?: 0; + } + } + + parent::setObjectTypeRelations($data); + } +} diff --git a/wcfsetup/install/files/lib/acp/page/LabelGroupListPage.class.php b/wcfsetup/install/files/lib/acp/page/LabelGroupListPage.class.php new file mode 100644 index 0000000000..ae7e2c0f67 --- /dev/null +++ b/wcfsetup/install/files/lib/acp/page/LabelGroupListPage.class.php @@ -0,0 +1,40 @@ + + * @package com.woltlab.wcf.label + * @subpackage acp.page + * @category Community Framework + */ +class LabelGroupListPage extends SortablePage { + /** + * @see wcf\page\AbstractPage::$activeMenuItem + */ + public $activeMenuItem = 'wcf.acp.menu.link.label.group.list'; + + /** + * @see wcf\page\SortablePage::$defaultSortField + */ + public $defaultSortField = 'groupName'; + + /** + * @see wcf\page\SortablePage::$validSortFields + */ + public $validSortFields = array('groupID', 'groupName'); + + /** + * @see wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array('admin.content.label.canManageLabel'); + + /** + * @see wcf\page\MultipleLinkPage::$objectListClassName + */ + public $objectListClassName = 'wcf\data\label\group\LabelGroupList'; +} diff --git a/wcfsetup/install/files/lib/acp/page/LabelListPage.class.php b/wcfsetup/install/files/lib/acp/page/LabelListPage.class.php new file mode 100644 index 0000000000..c77ebeaec1 --- /dev/null +++ b/wcfsetup/install/files/lib/acp/page/LabelListPage.class.php @@ -0,0 +1,50 @@ + + * @package com.woltlab.wcf.label + * @subpackage acp.page + * @category Community Framework + */ +class LabelListPage extends SortablePage { + /** + * @see wcf\page\AbstractPage::$activeMenuItem + */ + public $activeMenuItem = 'wcf.acp.menu.link.label.list'; + + /** + * @see wcf\page\SortablePage::$defaultSortField + */ + public $defaultSortField = 'label'; + + /** + * @see wcf\page\SortablePage::$validSortFields + */ + public $validSortFields = array('labelID', 'label', 'groupName'); + + /** + * @see wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array('admin.content.label.canManageLabel'); + + /** + * @see wcf\page\MultipleLinkPage::$objectListClassName + */ + public $objectListClassName = 'wcf\data\label\LabelList'; + + /** + * @see wcf\page\MultipleLinkPage::initObjectList() + */ + protected function initObjectList() { + parent::initObjectList(); + + $this->objectList->sqlSelects = "label_group.groupName"; + $this->objectList->sqlJoins = "LEFT JOIN wcf".WCF_N."_label_group label_group ON (label_group.groupID = label.groupID)"; + } +} diff --git a/wcfsetup/install/files/lib/data/label/Label.class.php b/wcfsetup/install/files/lib/data/label/Label.class.php new file mode 100644 index 0000000000..c723ec3048 --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/Label.class.php @@ -0,0 +1,70 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label + * @category Community Framework + */ +class Label extends DatabaseObject implements IRouteController { + /** + * @see wcf\data\DatabaseObject::$databaseTableName + */ + protected static $databaseTableName = 'label'; + + /** + * @see wcf\data\DatabaseObject::$databaseIndexName + */ + protected static $databaseTableIndexName = 'labelID'; + + /** + * Returns the label's textual representation if a label is treated as a + * string. + * + * @return string + */ + public function __toString() { + return $this->getTitle(); + } + + /** + * Returns true, if label is editable by current user. + * + * @return boolean + */ + public function isEditable() { + if (WCF::getSession()->getPermission('admin.content.label.canManageLabel')) { + return true; + } + + return false; + } + + /** + * Returns true, if label is deletable by current user. + * + * @return boolean + */ + public function isDeletable() { + if (WCF::getSession()->getPermission('admin.content.label.canManageLabel')) { + return true; + } + + return false; + } + + /** + * @see wcf\data\ITitledObject::getTitle() + */ + public function getTitle() { + return WCF::getLanguage()->get($this->label); + } +} diff --git a/wcfsetup/install/files/lib/data/label/LabelAction.class.php b/wcfsetup/install/files/lib/data/label/LabelAction.class.php new file mode 100644 index 0000000000..97e3bf0312 --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/LabelAction.class.php @@ -0,0 +1,74 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label + * @category Community Framework + */ +class LabelAction extends AbstractDatabaseObjectAction { + /** + * @see wcf\data\AbstractDatabaseObjectAction::$className + */ + protected $className = 'wcf\data\label\LabelEditor'; + + /** + * @see wcf\data\AbstractDatabaseObjectAction::$permissionsCreate + */ + protected $permissionsCreate = array('admin.content.label.canManageLabel'); + + /** + * @see wcf\data\AbstractDatabaseObjectAction::$permissionsDelete + */ + protected $permissionsDelete = array('admin.content.label.canManageLabel'); + + /** + * @see wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate + */ + protected $permissionsUpdate = array('admin.content.label.canManageLabel'); + + /** + * @see wcf\data\AbstractDatabaseObjectAction::delete() + */ + public function delete() { + parent::delete(); + + if (!empty($this->objects)) { + // identify i18n labels + $languageVariables = array(); + foreach ($this->objects as $object) { + if (preg_match('~wcf.acp.label.label\d+~', $object->label)) { + $languageVariables[] = $object->label; + } + } + + // remove language variables + if (!empty($languageVariables)) { + $conditions = new PreparedStatementConditionBuilder(); + $conditions->add("languageItem IN (?)", array($languageVariables)); + + $sql = "SELECT languageItemID + FROM wcf".WCF_N."_language_item + ".$conditions; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute($conditions->getParameters()); + $languageItemIDs = array(); + while ($row = $statement->fetchArray()) { + $languageItemIDs[] = $row['languageItemID']; + } + + $objectAction = new LanguageItemAction($languageItemIDs, 'delete'); + $objectAction->executeAction(); + } + } + } +} diff --git a/wcfsetup/install/files/lib/data/label/LabelEditor.class.php b/wcfsetup/install/files/lib/data/label/LabelEditor.class.php new file mode 100644 index 0000000000..d2c4262d22 --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/LabelEditor.class.php @@ -0,0 +1,29 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label + * @category Community Framework + */ +class LabelEditor extends DatabaseObjectEditor implements IEditableCachedObject { + /** + * @see wcf\data\DatabaseObjectEditor::$baseClass + */ + protected static $baseClass = 'wcf\data\label\Label'; + + /** + * @see wcf\data\IEditableCachedObject::resetCache() + */ + public static function resetCache() { + LabelCacheBuilder::getInstance()->reset(); + } +} diff --git a/wcfsetup/install/files/lib/data/label/LabelList.class.php b/wcfsetup/install/files/lib/data/label/LabelList.class.php new file mode 100644 index 0000000000..de35b94de0 --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/LabelList.class.php @@ -0,0 +1,20 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label + * @category Community Framework + */ +class LabelList extends DatabaseObjectList { + /** + * @see wcf\data\DatabaseObjectList::$className + */ + public $className = 'wcf\data\label\Label'; +} diff --git a/wcfsetup/install/files/lib/data/label/group/LabelGroup.class.php b/wcfsetup/install/files/lib/data/label/group/LabelGroup.class.php new file mode 100644 index 0000000000..2c57c9c3ad --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/group/LabelGroup.class.php @@ -0,0 +1,60 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label.group + * @category Community Framework + */ +class LabelGroup extends DatabaseObject implements IRouteController { + /** + * @see wcf\data\DatabaseObject::$databaseTableName + */ + protected static $databaseTableName = 'label_group'; + + /** + * @see wcf\data\DatabaseObject::$databaseIndexName + */ + protected static $databaseTableIndexName = 'groupID'; + + /** + * Returns true, if label is editable by current user. + * + * @return boolean + */ + public function isEditable() { + if (WCF::getSession()->getPermission('admin.content.label.canManageLabel')) { + return true; + } + + return false; + } + + /** + * Returns true, if label is deletable by current user. + * + * @return boolean + */ + public function isDeletable() { + if (WCF::getSession()->getPermission('admin.content.label.canManageLabel')) { + return true; + } + + return false; + } + + /** + * @see wcf\data\ITitledObject::getTitle() + */ + public function getTitle() { + return $this->groupName; + } +} diff --git a/wcfsetup/install/files/lib/data/label/group/LabelGroupAction.class.php b/wcfsetup/install/files/lib/data/label/group/LabelGroupAction.class.php new file mode 100644 index 0000000000..f14f1db44f --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/group/LabelGroupAction.class.php @@ -0,0 +1,35 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label.group + * @category Community Framework + */ +class LabelGroupAction extends AbstractDatabaseObjectAction { + /** + * @see wcf\data\AbstractDatabaseObjectAction::$className + */ + protected $className = 'wcf\data\label\group\LabelGroupEditor'; + + /** + * @see wcf\data\AbstractDatabaseObjectAction::$permissionsCreate + */ + protected $permissionsCreate = array('admin.content.label.canManageLabel'); + + /** + * @see wcf\data\AbstractDatabaseObjectAction::$permissionsDelete + */ + protected $permissionsDelete = array('admin.content.label.canManageLabel'); + + /** + * @see wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate + */ + protected $permissionsUpdate = array('admin.content.label.canManageLabel'); +} diff --git a/wcfsetup/install/files/lib/data/label/group/LabelGroupEditor.class.php b/wcfsetup/install/files/lib/data/label/group/LabelGroupEditor.class.php new file mode 100644 index 0000000000..478cf60ef2 --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/group/LabelGroupEditor.class.php @@ -0,0 +1,43 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label.group + * @category Community Framework + */ +class LabelGroupEditor extends DatabaseObjectEditor implements IEditableCachedObject { + /** + * @see wcf\data\DatabaseObjectEditor::$baseClass + */ + protected static $baseClass = 'wcf\data\label\group\LabelGroup'; + + /** + * @see wcf\data\IEditableObject::deleteAll() + */ + public static function deleteAll(array $objectIDs = array()) { + $count = parent::deleteAll($objectIDs); + + // remove ACL values + $objectTypeID = ACLHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.label'); + ACLHandler::getInstance()->removeValues($objectTypeID, $objectIDs); + + return $count; + } + + /** + * @see wcf\data\IEditableCachedObject::resetCache() + */ + public static function resetCache() { + LabelCacheBuilder::getInstance()->reset(); + } +} diff --git a/wcfsetup/install/files/lib/data/label/group/LabelGroupList.class.php b/wcfsetup/install/files/lib/data/label/group/LabelGroupList.class.php new file mode 100644 index 0000000000..a2ecb1dbb8 --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/group/LabelGroupList.class.php @@ -0,0 +1,20 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label.group + * @category Community Framework + */ +class LabelGroupList extends DatabaseObjectList { + /** + * @see wcf\data\DatabaseObjectList::$className + */ + public $className = 'wcf\data\label\group\LabelGroup'; +} diff --git a/wcfsetup/install/files/lib/data/label/group/ViewableLabelGroup.class.php b/wcfsetup/install/files/lib/data/label/group/ViewableLabelGroup.class.php new file mode 100644 index 0000000000..9df525f01f --- /dev/null +++ b/wcfsetup/install/files/lib/data/label/group/ViewableLabelGroup.class.php @@ -0,0 +1,232 @@ + + * @package com.woltlab.wcf.label + * @subpackage data.label.group + * @category Community Framework + */ +class ViewableLabelGroup extends DatabaseObjectDecorator implements \Countable, ITraversableObject { + /** + * @see wcf\data\DatabaseObjectDecorator::$baseClass + */ + protected static $baseClass = 'wcf\data\label\group\LabelGroup'; + + /** + * list of labels + * @var array + */ + protected $labels = array(); + + /** + * list of permissions by type + * @var array + */ + protected $permissions = array( + 'group' => array(), + 'user' => array() + ); + + /** + * current iterator index + * @var integer + */ + protected $index = 0; + + /** + * list of index to object relation + * @var array + */ + protected $indexToObject = null; + + /** + * Adds a label. + * + * @param wcf\data\label\Label $label + */ + public function addLabel(Label $label) { + $this->labels[$label->labelID] = $label; + $this->indexToObject[] = $label->labelID; + } + + /** + * Sets group permissions. + * + * @param array $permissions + */ + public function setGroupPermissions(array $permissions) { + $this->permissions['group'] = $permissions; + } + + /** + * Sets user permissions. + * + * @param array $permissions + */ + public function setUserPermissions(array $permissions) { + $this->permissions['user'] = $permissions; + } + + /** + * Returns true, if label is known. + * + * @param integer $labelID + * @return boolean + */ + public function isValid($labelID) { + return isset($this->labels[$labelID]); + } + + /** + * Returns true, if current user fulfils option id permissions. + * + * @param integer $optionID + * @return boolean + */ + public function getPermission($optionID) { + // validate by user id + $userID = WCF::getUser()->userID; + if ($userID) { + if (isset($this->permissions['user'][$userID]) && isset($this->permissions['user'][$userID][$optionID])) { + if ($this->permissions['user'][$userID][$optionID] == 1) { + return true; + } + } + } + + // validate by group id + $groupIDs = WCF::getUser()->getGroupIDs(); + foreach ($groupIDs as $groupID) { + if (isset($this->permissions['group'][$groupID]) && isset($this->permissions['group'][$groupID][$optionID])) { + if ($this->permissions['group'][$groupID][$optionID] == 1) { + return true; + } + } + } + + return false; + } + + /** + * Returns a list of label ids. + * + * @return array + */ + public function getLabelIDs() { + return array_keys($this->labels); + } + + /** + * Returns a list of labels. + * + * @return array + */ + public function getLabels() { + return $this->labels; + } + + /** + * Returns a label by id. + * + * @param integer $labelID + * @return wcf\data\label\Label + */ + public function getLabel($labelID) { + if (isset($this->labels[$labelID])) { + return $this->labels[$labelID]; + } + + return null; + } + + /** + * @see \Countable::count() + */ + public function count() { + return count($this->labels); + } + + /** + * @see \Iterator::current() + */ + public function current() { + $objectID = $this->indexToObject[$this->index]; + return $this->labels[$objectID]; + } + + /** + * CAUTION: This methods does not return the current iterator index, + * rather than the object key which maps to that index. + * + * @see \Iterator::key() + */ + public function key() { + return $this->indexToObject[$this->index]; + } + + /** + * @see \Iterator::next() + */ + public function next() { + ++$this->index; + } + + /** + * @see \Iterator::rewind() + */ + public function rewind() { + $this->index = 0; + } + + /** + * @see \Iterator::valid() + */ + public function valid() { + return isset($this->indexToObject[$this->index]); + } + + /** + * @see \SeekableIterator::seek() + */ + public function seek($index) { + $this->index = $index; + + if (!$this->valid()) { + throw new \OutOfBoundsException(); + } + } + + /** + * @see wcf\data\ITraversableObject::seekTo() + */ + public function seekTo($objectID) { + $this->index = array_search($objectID, $this->indexToObject); + + if ($this->index === false) { + throw new SystemException("object id '".$objectID."' is invalid"); + } + } + + /** + * @see wcf\data\ITraversableObject::search() + */ + public function search($objectID) { + try { + $this->seekTo($objectID); + return $this->current(); + } + catch (SystemException $e) { + return null; + } + } +} diff --git a/wcfsetup/install/files/lib/system/cache/builder/LabelCacheBuilder.class.php b/wcfsetup/install/files/lib/system/cache/builder/LabelCacheBuilder.class.php new file mode 100644 index 0000000000..dd758cd85a --- /dev/null +++ b/wcfsetup/install/files/lib/system/cache/builder/LabelCacheBuilder.class.php @@ -0,0 +1,70 @@ + + * @package com.woltlab.wcf.label + * @subpackage system.cache.builder + * @category Community Framework + */ +class LabelCacheBuilder extends AbstractCacheBuilder { + /** + * @see wcf\system\cache\builder\AbstractCacheBuilder::rebuild() + */ + protected function rebuild(array $parameters) { + $data = array( + 'options' => array(), + 'groups' => array() + ); + + // get label groups + $groupList = new LabelGroupList(); + $groupList->readObjects(); + $groups = $groupList->getObjects(); + foreach ($groups as &$group) { + $data['groups'][$group->groupID] = new ViewableLabelGroup($group); + } + unset($group); + + // get permissions for groups + $permissions = ACLHandler::getInstance()->getPermissions( + ACLHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.label'), + array_keys($data['groups']) + ); + + // store options + $data['options'] = $permissions['options']->getObjects(); + + // assign permissions for each label group + foreach ($data['groups'] as $groupID => $group) { + // group permissions + if (isset($permissions['group'][$groupID])) { + $group->setGroupPermissions($permissions['group'][$groupID]); + } + + // user permissions + if (isset($permissions['user'][$groupID])) { + $group->setUserPermissions($permissions['user'][$groupID]); + } + } + + if (count($groupList)) { + // get labels + $labelList = new LabelList(); + $labelList->readObjects(); + foreach ($labelList as $label) { + $data['groups'][$label->groupID]->addLabel($label); + } + } + + return $data; + } +} diff --git a/wcfsetup/install/files/lib/system/label/LabelHandler.class.php b/wcfsetup/install/files/lib/system/label/LabelHandler.class.php new file mode 100644 index 0000000000..f014d1ff41 --- /dev/null +++ b/wcfsetup/install/files/lib/system/label/LabelHandler.class.php @@ -0,0 +1,333 @@ + + * @package com.woltlab.wcf.label + * @subpackage system.label + * @category Community Framework + */ +class LabelHandler extends SingletonFactory { + /** + * cached list of object types + * @var array + */ + protected $cache = null; + + /** + * list of label groups + * @var array + */ + protected $labelGroups = null; + + /** + * @see wcf\system\SingletonFactory::init() + */ + protected function init() { + $this->cache = array( + 'objectTypes' => array(), + 'objectTypeNames' => array() + ); + + $cache = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.label.object'); + foreach ($cache as $objectType) { + $this->cache['objectTypes'][$objectType->objectTypeID] = $objectType; + $this->cache['objectTypeNames'][$objectType->objectType] = $objectType->objectTypeID; + } + + $this->labelGroups = LabelCacheBuilder::getInstance()->getData(); + } + + /** + * Returns the id of the label ACL option with the given name or null if + * no such option exists. + * + * @param string $optionName + * @return integer + */ + public function getOptionID($optionName) { + foreach ($this->labelGroups['options'] as $option) { + if ($option->optionName == $optionName) { + return $option->optionID; + } + } + + return null; + } + + /** + * Returns the label object type with the given name or null of no such + * object. + * + * @param string $objectType + * @return wcf\data\object\type\ObjectType + */ + public function getObjectType($objectType) { + if (isset($this->cache['objectTypeNames'][$objectType])) { + $objectTypeID = $this->cache['objectTypeNames'][$objectType]; + return $this->cache['objectTypes'][$objectTypeID]; + } + + return null; + } + + /** + * Returns an array with view permissions for the labels with the given id. + * + * @param array $labelIDs + * @return array + * @see wcf\system\label\LabelHandler::getPermissions() + */ + public function validateCanView(array $labelIDs) { + return $this->getPermissions('canViewLabel', $labelIDs); + } + + /** + * Returns an array with use permissions for the labels with the given id. + * + * @param array $labelIDs + * @return array + * @see wcf\system\label\LabelHandler::getPermissions() + */ + public function validateCanUse(array $labelIDs) { + return $this->getPermissions('canUseLabel', $labelIDs); + } + + /** + * Returns an array with boolean values for each given label id. + * + * @param string $optionName + * @param array $labelIDs + * @return array + */ + public function getPermissions($optionName, array $labelIDs) { + if (empty($labelIDs)) { + // nothing to validate anyway + return array(); + } + + if (empty($this->labelGroups['groups'])) { + // pretend given label ids aren't valid + $data = array(); + foreach ($labelIDs as $labelID) $data[$labelID] = false; + + return $data; + } + + $optionID = $this->getOptionID($optionName); + if ($optionID === null) { + throw new SystemException("cannot validate label ids, ACL options missing"); + } + + // validate each label + $data = array(); + foreach ($labelIDs as $labelID) { + $isValid = false; + + foreach ($this->labelGroups['groups'] as $group) { + if (!$group->isValid($labelID)) { + continue; + } + + if ($group->getPermission($optionID)) { + $isValid = true; + } + } + + $data[$labelID] = $isValid; + } + + return $data; + } + + /** + * Sets labels for given object id, pass an empty array to remove all previously + * assigned labels. + * + * @param array $labelIDs + * @param integer $objectTypeID + * @param integer $objectID + * @param boolean $validatePermissions + */ + public function setLabels(array $labelIDs, $objectTypeID, $objectID, $validatePermissions = true) { + // get accessible label ids to prevent unaccessible ones to be removed + $accessibleLabelIDs = $this->getAccessibleLabelIDs(); + + // delete previous labels + $conditions = new PreparedStatementConditionBuilder(); + if ($validatePermissions) $conditions->add("labelID IN (?)", array($accessibleLabelIDs)); + $conditions->add("objectTypeID = ?", array($objectTypeID)); + $conditions->add("objectID = ?", array($objectID)); + + if (!$validatePermissions || ($validatePermissions && !empty($accessibleLabelIDs))) { + $sql = "DELETE FROM wcf".WCF_N."_label_object + ".$conditions; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute($conditions->getParameters()); + } + + // insert new labels + if (!empty($labelIDs)) { + $sql = "INSERT INTO wcf".WCF_N."_label_object + (labelID, objectTypeID, objectID) + VALUES (?, ?, ?)"; + $statement = WCF::getDB()->prepareStatement($sql); + foreach ($labelIDs as $labelID) { + $statement->execute(array( + $labelID, + $objectTypeID, + $objectID + )); + } + } + } + + /** + * Returns all assigned labels, optionally filtered to validate permissions. + * + * @param integer $objectTypeID + * @param array $objectIds + * @param boolean $validatePermissions + * @return array + */ + public function getAssignedLabels($objectTypeID, array $objectIDs, $validatePermissions = true) { + $conditions = new PreparedStatementConditionBuilder(); + $conditions->add("objectTypeID = ?", array($objectTypeID)); + $conditions->add("objectID IN (?)", array($objectIDs)); + $sql = "SELECT objectID, labelID + FROM wcf".WCF_N."_label_object + ".$conditions; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute($conditions->getParameters()); + + $labels = array(); + while ($row = $statement->fetchArray()) { + if (!isset($labels[$row['labelID']])) { + $labels[$row['labelID']] = array(); + } + + $labels[$row['labelID']][] = $row['objectID']; + } + + // optionally filter out labels without permissions + if ($validatePermissions) { + $labelIDs = array_keys($labels); + $result = $this->validateCanView($labelIDs); + + foreach ($labelIDs as $labelID) { + if (!$result[$labelID]) { + unset($labels[$labelID]); + } + } + } + + // reorder the array by object id + $data = array(); + foreach ($labels as $labelID => $objectIDs) { + foreach ($objectIDs as $objectID) { + if (!isset($data[$objectID])) { + $data[$objectID] = array(); + } + + foreach ($this->labelGroups['groups'] as $group) { + $label = $group->getLabel($labelID); + if ($label !== null) { + $data[$objectID][$labelID] = $label; + } + } + } + } + + return $data; + } + + /** + * Removes all previously assigned labels. + * + * @param integer $objectTypeID + * @param integer $objectID + * @param boolean $validatePermissions + * @see wcf\system\label\LabelHandler::setLabel() + */ + public function removeLabels($objectTypeID, $objectID, $validatePermissions = true) { + $this->setLabel(array(), $objectTypeID, $objectID, $validatePermissions); + } + + /** + * Returns given label groups by id. + * + * @param array $groupID + * @param boolean $validatePermissions + * @param string $permission + * @return array + */ + public function getLabelGroups(array $groupIDs = array(), $validatePermissions = true, $permission = 'canSetLabel') { + $data = array(); + + if ($validatePermissions) { + $optionID = $this->getOptionID($permission); + if ($optionID === null) { + throw new SystemException("cannot validate group ids, ACL options missing"); + } + } + + if (empty($groupIDs)) $groupIDs = array_keys($this->labelGroups['groups']); + foreach ($groupIDs as $groupID) { + // validate given group ids + if (!isset($this->labelGroups['groups'][$groupID])) { + throw new SystemException("unknown label group identified by group id '".$groupID."'"); + } + + // validate permissions + if ($validatePermissions) { + if (!$this->labelGroups['groups'][$groupID]->getPermission($optionID)) { + continue; + } + } + + $data[$groupID] = $this->labelGroups['groups'][$groupID]; + } + + return $data; + } + + /** + * Returns a list of accessible label ids. + * + * @return array + */ + public function getAccessibleLabelIDs() { + $labelIDs = array(); + $groups = $this->getLabelGroups(); + + foreach ($groups as $group) { + $labelIDs = array_merge($labelIDs, $group->getLabelIDs()); + } + + return $labelIDs; + } + + /** + * Returns label group by id. + * + * @param integer $groupID + * @return wcf\data\label\group\ViewableLabelGroup + */ + public function getLabelGroup($groupID) { + if (isset($this->labelGroups['groups'][$groupID])) { + return $this->labelGroups['groups'][$groupID]; + } + + return null; + } +} diff --git a/wcfsetup/install/files/lib/system/label/object/AbstractLabelObjectHandler.class.php b/wcfsetup/install/files/lib/system/label/object/AbstractLabelObjectHandler.class.php new file mode 100644 index 0000000000..1c7e5dcd56 --- /dev/null +++ b/wcfsetup/install/files/lib/system/label/object/AbstractLabelObjectHandler.class.php @@ -0,0 +1,137 @@ + + * @package com.woltlab.wcf.label + * @subpackage system.label.object + * @category Community Framework + */ +abstract class AbstractLabelObjectHandler extends SingletonFactory implements ILabelObjectHandler { + /** + * list of available label groups + * @var array + */ + protected $labelGroups = array(); + + /** + * object type name + * @var string + */ + protected $objectType = ''; + + /** + * object type id + * @var integer + */ + protected $objectTypeID = 0; + + /** + * @see wcf\system\SingletonFactory::init() + */ + protected function init() { + $this->labelGroups = LabelHandler::getInstance()->getLabelGroups(); + + $objectType = LabelHandler::getInstance()->getObjectType($this->objectType); + if ($objectType === null) { + throw new SystemException("object type '".$this->objectType."' is invalid"); + } + $this->objectTypeID = $objectType->objectTypeID; + } + + /** + * @see wcf\system\label\manager\ILabelObjectHandler::getLabelGroupIDs() + */ + public function getLabelGroupIDs(array $parameters = array()) { + return array_keys($this->labelGroups); + } + + /** + * @see wcf\system\label\manager\ILabelObjectHandler::getLabelGroups() + */ + public function getLabelGroups(array $parameters = array()) { + $groupIDs = $this->getLabelGroupIDs($parameters); + + $data = array(); + foreach ($groupIDs as $groupID) { + $data[$groupID] = $this->labelGroups[$groupID]; + } + + return $data; + } + + /** + * @see wcf\system\label\manager\ILabelObjectHandler::validateLabelIDs() + */ + public function validateLabelIDs(array $labelIDs, $optionName = '') { + $optionID = 0; + if (!empty($optionName)) { + $optionID = LabelHandler::getInstance()->getOptionID($optionName); + if ($optionID === null) { + throw new SystemException("Cannot validate label permissions, option '".$optionName."' is unknown"); + } + } + + $satisfiedGroups = array(); + foreach ($labelIDs as $groupID => $labelID) { + // only one label per group is allowed + if (is_array($labelID)) { + return false; + } + + // label group id is unknown or label id is invalid for this group + if (!isset($this->labelGroups[$groupID]) || !$this->labelGroups[$groupID]->isValid($labelID)) { + return false; + } + + // check permission + if ($optionID && !$this->labelGroups[$groupID]->getPermission($optionID)) { + return false; + } + + $satisfiedGroups[] = $groupID; + } + + // check if required label groups were set + foreach ($this->labelGroups as $labelGroup) { + if ($labelGroup->forceSelection && !in_array($labelGroup->groupID, $satisfiedGroups)) { + // check if group wasn't set, but is not accessible for this user anyway + if (!$labelGroup->getPermission($optionID)) { + continue; + } + + return false; + } + } + + return true; + } + + /** + * @see wcf\system\label\manager\ILabelObjectHandler::setLabels() + */ + public function setLabels(array $labelIDs, $objectID, $validatePermissions = true) { + LabelHandler::getInstance()->setLabels($labelIDs, $this->objectTypeID, $objectID, $validatePermissions); + } + + /** + * @see wcf\system\label\manager\ILabelObjectHandler::removeLabels() + */ + public function removeLabels($objectID, $validatePermissions = true) { + LabelHandler::getInstance()->removeLabels($this->objectTypeID, $objectID, $validatePermissions); + } + + /** + * @see wcf\system\label\manager\ILabelObjectHandler::getAssignedLabels() + */ + public function getAssignedLabels(array $objectIDs, $validatePermissions = true) { + return LabelHandler::getInstance()->getAssignedLabels($this->objectTypeID, $objectIDs, $validatePermissions); + } +} diff --git a/wcfsetup/install/files/lib/system/label/object/ILabelObjectHandler.class.php b/wcfsetup/install/files/lib/system/label/object/ILabelObjectHandler.class.php new file mode 100644 index 0000000000..a9dd9b284c --- /dev/null +++ b/wcfsetup/install/files/lib/system/label/object/ILabelObjectHandler.class.php @@ -0,0 +1,67 @@ + + * @package com.woltlab.wcf.label + * @subpackage system.label.object + * @category Community Framework + */ +interface ILabelObjectHandler { + /** + * Returns a list of label group ids. + * + * @param array $parameters + * @return array + */ + public function getLabelGroupIDs(array $parameters = array()); + + /** + * Returns a list of label groups. + * + * @param array $parameters + * @return array + */ + public function getLabelGroups(array $parameters = array()); + + /** + * Returns true, if all given label ids are valid and accessible. + * + * @param array $labelIDs + * @param array $optionName + * @return boolean + */ + public function validateLabelIDs(array $labelIDs, $optionName = ''); + + /** + * Assigns labels to an object. + * + * @param array $labelIDs + * @param integer $objectID + * @param boolean $validatePermissions + * @see wcf\system\label\LabelHandler::setLabels() + */ + public function setLabels(array $labelIDs, $objectID, $validatePermissions = true); + + /** + * Removes all assigned labels. + * + * @param integer $objectID + * @param boolean $validatePermissions + * @see wcf\system\label\LabelHandler::removeLabels() + */ + public function removeLabels($objectID, $validatePermissions = true); + + /** + * Returns a list of assigned labels. + * + * @param array $objectIDs + * @param boolean $validatePermissions + * @return array + */ + public function getAssignedLabels(array $objectIDs, $validatePermissions = true); +} diff --git a/wcfsetup/install/files/lib/system/label/object/type/AbstractLabelObjectTypeHandler.class.php b/wcfsetup/install/files/lib/system/label/object/type/AbstractLabelObjectTypeHandler.class.php new file mode 100644 index 0000000000..7fae26197b --- /dev/null +++ b/wcfsetup/install/files/lib/system/label/object/type/AbstractLabelObjectTypeHandler.class.php @@ -0,0 +1,48 @@ + + * @package com.woltlab.wcf.label + * @subpackage system.label.object.type + * @category Community Framework + */ +abstract class AbstractLabelObjectTypeHandler extends SingletonFactory implements ILabelObjectTypeHandler { + /** + * label object type container + * @var wcf\system\label\object\type\LabelObjectTypeContainer + */ + public $container = null; + + /** + * object type id + * @var integer + */ + public $objectTypeID = 0; + + /** + * @see wcf\system\label\object\type\ILabelObjectTypeHandler::setObjectTypeID() + */ + public function setObjectTypeID($objectTypeID) { + $this->objectTypeID = $objectTypeID; + } + + /** + * @see wcf\system\label\object\type\ILabelObjectTypeHandler::getObjectTypeID() + */ + public function getObjectTypeID() { + return $this->objectTypeID; + } + + /** + * @see wcf\system\label\object\type\ILabelObjectTypeHandler::getContainer() + */ + public function getContainer() { + return $this->container; + } +} diff --git a/wcfsetup/install/files/lib/system/label/object/type/ILabelObjectTypeHandler.class.php b/wcfsetup/install/files/lib/system/label/object/type/ILabelObjectTypeHandler.class.php new file mode 100644 index 0000000000..3557428fb9 --- /dev/null +++ b/wcfsetup/install/files/lib/system/label/object/type/ILabelObjectTypeHandler.class.php @@ -0,0 +1,40 @@ + + * @package com.woltlab.wcf.label + * @subpackage system.label.object.type + * @category Community Framework + */ +interface ILabelObjectTypeHandler { + /** + * Sets object type id. + * + * @param integer $objectTypeID + */ + public function setObjectTypeID($objectTypeID); + + /** + * Returns object type id. + * + * @return integer + */ + public function getObjectTypeID(); + + /** + * Returns a label object type container. + * + * @return wcf\system\label\object\type\LabelObjectTypeContainer + */ + public function getContainer(); + + /** + * Performs save actions. + */ + public function save(); +} diff --git a/wcfsetup/install/files/lib/system/label/object/type/LabelObjectType.class.php b/wcfsetup/install/files/lib/system/label/object/type/LabelObjectType.class.php new file mode 100644 index 0000000000..43d60c27af --- /dev/null +++ b/wcfsetup/install/files/lib/system/label/object/type/LabelObjectType.class.php @@ -0,0 +1,112 @@ + + * @package com.woltlab.wcf.label + * @subpackage system.label.object.type + * @category Community Framework + */ +class LabelObjectType { + /** + * indentation level + * @var integer + */ + public $depth = 0; + + /** + * object type is a category + * @var boolean + */ + public $isCategory = false; + + /** + * object type label + * @var string + */ + public $label = ''; + + /** + * object id + * @var integer + */ + public $objectID = 0; + + /** + * option value + * @var integer + */ + public $optionValue = 0; + + /** + * Creates a new LabelObjectType object. + * + * @param string $label + * @param integer $objectID + * @param integer $depth + * @param boolean $isCategory + */ + public function __construct($label, $objectID = 0, $depth = 0, $isCategory = false) { + $this->depth = $depth; + $this->isCategory = $isCategory; + $this->label = $label; + $this->objectID = $objectID; + } + + /** + * Returns the label. + * + * @return string + */ + public function getLabel() { + return $this->label; + } + + /** + * Returns the object id. + * @return integer + */ + public function getObjectID() { + return $this->objectID; + } + + /** + * Returns true, if object type is a category. + * + * @return boolean + */ + public function isCategory() { + return $this->isCategory; + } + + /** + * Returns indentation level. + * + * @return integer + */ + public function getDepth() { + return $this->depth; + } + + /** + * Sets option value. + * + * @param integer $optionValue + */ + public function setOptionValue($optionValue) { + $this->optionValue = $optionValue; + } + + /** + * Returns option value. + * + * @return integer + */ + public function getOptionValue() { + return $this->optionValue; + } +} diff --git a/wcfsetup/install/files/lib/system/label/object/type/LabelObjectTypeContainer.class.php b/wcfsetup/install/files/lib/system/label/object/type/LabelObjectTypeContainer.class.php new file mode 100644 index 0000000000..32061d48f4 --- /dev/null +++ b/wcfsetup/install/files/lib/system/label/object/type/LabelObjectTypeContainer.class.php @@ -0,0 +1,135 @@ + + * @package com.woltlab.wcf.label + * @subpackage system.label.object.type + * @category Community Framework + */ +class LabelObjectTypeContainer implements \Countable, \Iterator { + /** + * true if container represents only a boolean option + * @var boolean + */ + public $isBooleanOption = false; + + /** + * list of object types + * @var array + */ + public $objectTypes = array(); + + /** + * object type id + * @var integer + */ + public $objectTypeID = 0; + + /** + * option value if container is a boolean option itself + * @var boolean + */ + public $optionValue = false; + + /** + * iterator position + * @var integer + */ + private $position = 0; + + /** + * Creates a new LabelObjectTypeContainer object. + * + * @param integer $objectTypeID + * @param boolean $isBooleanOption + * @param boolean $optionValue + */ + public function __construct($objectTypeID, $isBooleanOption = false, $optionValue = false) { + $this->objectTypeID = $objectTypeID; + $this->isBooleanOption = $isBooleanOption; + $this->optionValue = $optionValue; + } + + /** + * Adds a label object type. + * + * @param wcf\system\label\object\type\LabelObjectType $objectType + */ + public function add(LabelObjectType $objectType) { + $this->objectTypes[] = $objectType; + } + + /** + * Returns the object type id. + * + * @return integer + */ + public function getObjectTypeID() { + return $this->objectTypeID; + } + + /** + * Returns true, if container represents only a boolean option. + * + * @return boolean + */ + public function isBooleanOption() { + return $this->isBooleanOption; + } + + /** + * Returns option value. + * + * @return boolean + */ + public function getOptionValue() { + return $this->optionValue; + } + + /** + * @see \Iterator::current() + */ + public function current() { + return $this->objectTypes[$this->position]; + } + + /** + * @see \Iterator::key() + */ + public function key() { + return $this->position; + } + + /** + * @see \Iterator::next() + */ + public function next() { + $this->position++; + } + + /** + * @see \Iterator::rewind() + */ + public function rewind() { + $this->position = 0; + } + + /** + * @see \Iterator::valid() + */ + public function valid() { + return isset($this->objectTypes[$this->position]); + } + + /** + * @see \Countable::count() + */ + public function count() { + return count($this->objectTypes); + } +} diff --git a/wcfsetup/install/files/style/label.less b/wcfsetup/install/files/style/label.less new file mode 100644 index 0000000000..576a4b1dcb --- /dev/null +++ b/wcfsetup/install/files/style/label.less @@ -0,0 +1,37 @@ +/* #### Labels #### */ +/* todo: move into wcf */ + +/* label list */ +.labelList, .labelList > li { + display: inline-block; +} + +/* ACP label list */ +#labelList { + .clearfix(); + + li { + float: left; + margin-right: 1%; + width: 30%; + + &.labelCustomClass { + position: relative; + + input[type='radio'] { + left: 0; + position: absolute; + top: 0; + } + + span { + display: block; + margin-left: 24px; + } + } + } +} + +.labelChooser > .dropdownToggle > span { + cursor: pointer; +} \ No newline at end of file diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 22faf708bd..5826fad394 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -10,6 +10,11 @@
    + + + + + @@ -304,6 +309,8 @@ + + @@ -326,6 +333,27 @@ + + + + + + Labelgruppe hinzufügen.]]> + + + + + + + + + + + groupName}“ wirklich löschen?]]> + + + + @@ -452,6 +480,11 @@ + + + + + @@ -1519,6 +1552,14 @@ Erlaubte Dateiendungen: {', '|implode:$attachmentHandler->getAllowedExtensions() + + + + + + + + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 25b234c65b..193ba8c37c 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -10,6 +10,11 @@ + + + + + @@ -303,6 +308,8 @@ Examples for medium ID detection: + + @@ -325,6 +332,27 @@ Examples for medium ID detection: + + + + + + add a label group prior to creating labels.]]> + + + + + + + + + + + groupName}”?]]> + + + + @@ -451,6 +479,11 @@ Examples for medium ID detection: + + + + + @@ -1517,6 +1550,14 @@ Allowed extensions: {', '|implode:$attachmentHandler->getAllowedExtensions()}]]> + + + + + + + + diff --git a/wcfsetup/setup/db/install.sql b/wcfsetup/setup/db/install.sql index 257c15ab9e..038e6d2e95 100644 --- a/wcfsetup/setup/db/install.sql +++ b/wcfsetup/setup/db/install.sql @@ -326,6 +326,38 @@ CREATE TABLE wcf1_event_listener ( UNIQUE KEY packageID (packageID, environment, eventClassName, eventName, listenerClassName) ); +DROP TABLE IF EXISTS wcf1_label; +CREATE TABLE wcf1_label ( + labelID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, + groupID INT(10) NOT NULL, + label VARCHAR(80) NOT NULL, + cssClassName VARCHAR(255) NOT NULL +); + +DROP TABLE IF EXISTS wcf1_label_group; +CREATE TABLE wcf1_label_group ( + groupID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, + groupName VARCHAR(80) NOT NULL, + forceSelection TINYINT(1) NOT NULL DEFAULT 0, +); + +DROP TABLE IF EXISTS wcf1_label_group_to_object; +CREATE TABLE wcf1_label_group_to_object ( + groupID INT(10) NOT NULL, + objectTypeID INT(10) NOT NULL, + objectID INT(10) NULL +); + +DROP TABLE IF EXISTS wcf1_label_object; +CREATE TABLE wcf1_label_object ( + labelID INT(10) NOT NULL, + objectTypeID INT(10) NOT NULL, + objectID INT(10) NOT NULL, + + KEY (objectTypeID, labelID), + KEY (objectTypeID, objectID) +); + DROP TABLE IF EXISTS wcf1_language; CREATE TABLE wcf1_language ( languageID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -1384,6 +1416,14 @@ ALTER TABLE wcf1_comment ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ALTER TABLE wcf1_comment_response ADD FOREIGN KEY (commentID) REFERENCES wcf1_comment (commentID) ON DELETE CASCADE; ALTER TABLE wcf1_comment_response ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE SET NULL; +ALTER TABLE wcf1_label ADD FOREIGN KEY (groupID) REFERENCES wcf1_label_group (groupID) ON DELETE CASCADE; + +ALTER TABLE wcf1_label_group_to_object ADD FOREIGN KEY (groupID) REFERENCES wcf1_label_group (groupID) ON DELETE CASCADE; +ALTER TABLE wcf1_label_group_to_object ADD FOREIGN KEY (objectTypeID) REFERENCES wcf1_object_type (objectTypeID) ON DELETE CASCADE; + +ALTER TABLE wcf1_label_object ADD FOREIGN KEY (labelID) REFERENCES wcf1_label (labelID) ON DELETE CASCADE; +ALTER TABLE wcf1_label_object ADD FOREIGN KEY (objectTypeID) REFERENCES wcf1_object_type (objectTypeID) ON DELETE CASCADE; + /* default inserts */ -- default user groups