Add notice implementation
authorMatthias Schmidt <gravatronics@live.com>
Sat, 24 May 2014 09:45:07 +0000 (11:45 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Sat, 24 May 2014 09:45:07 +0000 (11:45 +0200)
37 files changed:
com.woltlab.wcf/acpMenu.xml
com.woltlab.wcf/coreObject.xml
com.woltlab.wcf/objectType.xml
com.woltlab.wcf/objectTypeDefinition.xml
com.woltlab.wcf/templates/headInclude.tpl
com.woltlab.wcf/templates/userNotice.tpl
com.woltlab.wcf/userGroupOption.xml
wcfsetup/install/files/acp/templates/noticeAdd.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/noticeList.tpl [new file with mode: 0644]
wcfsetup/install/files/js/WCF.js
wcfsetup/install/files/lib/acp/form/NoticeAddForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/NoticeEditForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/UserGroupAssignmentAddForm.class.php
wcfsetup/install/files/lib/acp/form/UserGroupAssignmentEditForm.class.php
wcfsetup/install/files/lib/acp/page/NoticeListPage.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/notice/Notice.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/notice/NoticeAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/notice/NoticeEditor.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/notice/NoticeList.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/cache/builder/NoticeCacheBuilder.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/condition/AbstractMultiSelectCondition.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/condition/ConditionHandler.class.php
wcfsetup/install/files/lib/system/condition/INoticeCondition.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/condition/MultiPageControllerCondition.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/condition/UserAvatarCondition.class.php
wcfsetup/install/files/lib/system/condition/UserEmailCondition.class.php
wcfsetup/install/files/lib/system/condition/UserGroupCondition.class.php
wcfsetup/install/files/lib/system/condition/UserIntegerPropertyCondition.class.php
wcfsetup/install/files/lib/system/condition/UserLanguageCondition.class.php
wcfsetup/install/files/lib/system/condition/UserOptionsCondition.class.php
wcfsetup/install/files/lib/system/condition/UserRegistrationDateCondition.class.php
wcfsetup/install/files/lib/system/condition/UserRegistrationDateIntervalCondition.class.php
wcfsetup/install/files/lib/system/condition/UserStateCondition.class.php
wcfsetup/install/files/lib/system/condition/UserUsernameCondition.class.php
wcfsetup/install/files/lib/system/notice/NoticeHandler.class.php [new file with mode: 0644]
wcfsetup/install/lang/de.xml
wcfsetup/setup/db/install.sql

index ff2be66be1e93b7cd3d8227cc822b8134782ff33..0c304a2093f59095f0e88abd5b1473719385cc9e 100644 (file)
                        <permissions>admin.attachment.canManageAttachment</permissions>
                </acpmenuitem>
                
+               <acpmenuitem name="wcf.acp.menu.link.notice">
+                       <parent>wcf.acp.menu.link.content</parent>
+                       <showorder>6</showorder>
+               </acpmenuitem>
+               <acpmenuitem name="wcf.acp.menu.link.notice.list">
+                       <controller><![CDATA[wcf\acp\page\NoticeListPage]]></controller>
+                       <parent>wcf.acp.menu.link.notice</parent>
+                       <permissions>admin.content.tag.canManageTag</permissions>
+               </acpmenuitem>
+               <acpmenuitem name="wcf.acp.menu.link.notice.add">
+                       <controller><![CDATA[wcf\acp\form\NoticeAddForm]]></controller>
+                       <parent>wcf.acp.menu.link.notice</parent>
+                       <permissions>admin.content.notice.canManageNotice</permissions>
+               </acpmenuitem>
+               
                <acpmenuitem name="wcf.acp.menu.link.community">
                        <showorder>5</showorder>
                </acpmenuitem>
index c5e4c53cae618869c71d188a7231489bea91684e..d02ca2b9c2b37d0024305fc6b3449610c355a8be 100644 (file)
@@ -49,5 +49,9 @@
                <coreobject>
                        <objectname><![CDATA[wcf\system\moderation\queue\ModerationQueueManager]]></objectname>
                </coreobject>
+               
+               <coreobject>
+                       <objectname><![CDATA[wcf\system\notice\NoticeHandler]]></objectname>
+               </coreobject>
        </import>
 </data>
index 30ff78e09c7e75c1335602d6d8f9169fabd28250..8597bdb9d20250c3c5f1b6fe1a37bfaa04810382 100644 (file)
                        <classname><![CDATA[wcf\page\UsersOnlineListPage]]></classname>
                </type>
                <!-- /pages -->
+               
+               <!-- notice conditions -->
+               <type>
+                       <name>com.woltlab.wcf.page.controller</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\MultiPageControllerCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.page</conditionobject>
+               </type>
+               
+               <type>
+                       <name>com.woltlab.wcf.user.username</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserUsernameCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>general</conditiongroup>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.email</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserEmailCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>general</conditiongroup>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.userGroup</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserGroupCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>general</conditiongroup>
+                       <includeguests>1</includeguests>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.languages</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserLanguageCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>general</conditiongroup>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.registrationDate</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserRegistrationDateCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>general</conditiongroup>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.registrationDateInterval</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserRegistrationDateIntervalCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>general</conditiongroup>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.avatar</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserAvatarCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>general</conditiongroup>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.state</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserStateCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>general</conditiongroup>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.activityPoints</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserIntegerPropertyCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>contents</conditiongroup>
+                       <propertyname>activityPoints</propertyname>
+                       <minvalue>0</minvalue>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.likesReceived</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserIntegerPropertyCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>contents</conditiongroup>
+                       <propertyname>likesReceived</propertyname>
+                       <minvalue>0</minvalue>
+               </type>
+               <type>
+                       <name>com.woltlab.wcf.user.userOptions</name>
+                       <definitionname>com.woltlab.wcf.condition.notice</definitionname>
+                       <classname><![CDATA[wcf\system\condition\UserOptionsCondition]]></classname>
+                       <conditionobject>com.woltlab.wcf.user</conditionobject>
+                       <conditiongroup>userOptions</conditiongroup>
+               </type>
+               <!-- /user group assignment conditions -->
        </import>
 </data>
index 13663605962a3958d2f64538972d43c50d6f0e82..e7793e32688767690483260e21179627fbedcfd1 100644 (file)
                <definition>
                        <name>com.woltlab.wcf.page</name>
                </definition>
+               
+               <definition>
+                       <name>com.woltlab.wcf.condition.notice</name>
+                       <interfacename><![CDATA[wcf\system\condition\INoticeCondition]]></interfacename>
+               </definition>
        </import>
 </data>
index ee5e4ba692fd6daa1e88de958f193d530612e074..ef500d988db6e4f16a7a85a26349f5e4dc1292d7 100644 (file)
                WCF.Date.Picker.init();
                new WCF.User.ProfilePreview();
                WCF.System.FlexibleMenu.init();
+               new WCF.Notice.Dismiss();
                
                {event name='javascriptInit'}
                
index 8e0b6d20fe6d63f7a220a90cb3398a49bfe88ce3..a4ba26f6a9f1fe4ec5cb39d483b7cc160270b4c4 100644 (file)
                <p class="warning">{lang}wcf.user.register.needActivation{/lang}</p>
        {/if}
        
+       {* todo: styling/visual appearence *}
+       {foreach from=$__wcf->getNoticeHandler()->getVisibleNotices() item='notice'}
+               <p class="info notice{if $notice->isDismissible} noticeDismissible{/if}">
+                       {if $notice->isDismissible}
+                               <span class="icon icon16 icon-remove pointer jsDismissNoticeButton jsTooltip" data-object-id="{$notice->noticeID}" title="{lang}wcf.notice.button.dismiss{/lang}" style="float: right;"></span>
+                       {/if}
+                       
+                       {if $notice->noticeUseHtml}{@$notice->notice|language}{else}{$notice->notice|language}{/if}
+               </p>
+       {/foreach}
+       
        {event name='userNotice'}
-</div>
\ No newline at end of file
+</div>
index 6c107425e2cc0e7bce4c4d849375a4557a0620d3..b682efa5d1592fa9bf841622df6de8fde99c99b3 100644 (file)
                        <category name="admin.content.tag">
                                <parent>admin.content</parent>
                        </category>
+                       <category name="admin.content.notice">
+                               <parent>admin.content</parent>
+                       </category>
                        
                        <category name="admin.community">
                                <parent>admin</parent>
@@ -627,6 +630,13 @@ png]]></defaultvalue>
                                <defaultvalue>0</defaultvalue>
                                <admindefaultvalue>1</admindefaultvalue>
                        </option>
+                       
+                       <option name="admin.content.notice.canManageNotice">
+                               <categoryname>admin.content.notice</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <admindefaultvalue>1</admindefaultvalue>
+                       </option>
                </options>
        </import>
 </data>
diff --git a/wcfsetup/install/files/acp/templates/noticeAdd.tpl b/wcfsetup/install/files/acp/templates/noticeAdd.tpl
new file mode 100644 (file)
index 0000000..7b735be
--- /dev/null
@@ -0,0 +1,146 @@
+{include file='header' pageTitle='wcf.acp.notice.'|concat:$action}
+
+<script data-relocate="true">
+       //<![CDATA[
+       $(function() {
+               WCF.TabMenu.init();
+       });
+       //]]>
+</script>
+
+<header class="boxHeadline">
+       <h1>{lang}wcf.acp.notice.{$action}{/lang}</h1>
+</header>
+
+{include file='formError'}
+
+{if $success|isset}
+       <p class="success">{lang}wcf.global.success.{$action}{/lang}</p>
+{/if}
+
+<div class="contentNavigation">
+       <nav>
+               <ul>
+                       <li><a href="{link controller='NoticeList'}{/link}" class="button"><span class="icon icon16 icon-list"></span> <span>{lang}wcf.acp.menu.link.notice.list{/lang}</span></a></li>
+                       
+                       {event name='contentNavigationButtons'}
+               </ul>
+       </nav>
+</div>
+
+<form method="post" action="{if $action == 'add'}{link controller='NoticeAdd'}{/link}{else}{link controller='NoticeEdit' object=$notice}{/link}{/if}">
+       <div class="container containerPadding marginTop">
+               <fieldset>
+                       <legend>{lang}wcf.global.form.data{/lang}</legend>
+                       
+                       <dl{if $errorField == 'noticeName'} class="formError"{/if}>
+                               <dt><label for="noticeName">{lang}wcf.global.name{/lang}</label></dt>
+                               <dd>
+                                       <input type="text" id="noticeName" name="noticeName" value="{$noticeName}" required="required" autofocus="autofocus" class="long" />
+                                       {if $errorField == 'noticeName'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.notice.noticeName.error.{$errorType}{/lang}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                               </dd>
+                       </dl>
+                       
+                       <dl{if $errorField == 'notice'} class="formError"{/if}>
+                               <dt><label for="notice">{lang}wcf.acp.notice.notice{/lang}</label></dt>
+                               <dd>
+                                       <textarea id="notice" name="notice" cols="40" rows="10">{$i18nPlainValues['notice']}</textarea>
+                                       {if $errorField == 'notice'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                       {elseif $errorType == 'multilingual'}
+                                                               {lang}wcf.global.form.error.multilingual{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.notice.notice.error.{$errorType}{/lang}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                               </dd>
+                       </dl>
+                       {include file='multipleLanguageInputJavascript' elementIdentifier='notice' forceSelection=false}
+                       
+                       <dl>
+                               <dt></dt>
+                               <dd>
+                                       <label><input type="checkbox" name="noticeUseHtml" value="1"{if $noticeUseHtml} checked="checked"{/if} /> {lang}wcf.acp.notice.noticeUseHtml{/lang}</label>
+                               </dd>
+                       </dl>
+                       
+                       <dl>
+                               <dt></dt>
+                               <dd>
+                                       <label><input type="checkbox" name="isDisabled" value="1"{if $isDisabled} checked="checked"{/if} /> {lang}wcf.acp.notice.isDisabled{/lang}</label>
+                               </dd>
+                       </dl>
+                       
+                       <dl>
+                               <dt><label for="position">{lang}wcf.acp.notice.showOrder{/lang}</label></dt>
+                               <dd>
+                                       <input type="number" id="showOrder" name="showOrder" value="{$showOrder}" class="tiny" min="0" />
+                                       <small>{lang}wcf.acp.notice.showOrder.description{/lang}</small>
+                               </dd>
+                       </dl>
+                       
+                       <dl>
+                               <dt></dt>
+                               <dd>
+                                       <label><input type="checkbox" name="isDismissible" value="1"{if $isDismissible} checked="checked"{/if} /> {lang}wcf.acp.notice.isDismissible{/lang}</label>
+                                       <small>{lang}wcf.acp.notice.isDismissible.description{/lang}</small>
+                               </dd>
+                       </dl>
+                       
+                       {if $action == 'edit' && $notice->isDismissible}
+                               <dl>
+                                       <dt></dt>
+                                       <dd>
+                                               <label><input type="checkbox" name="resetIsDismissed" value="1"{if $resetIsDismissed} checked="checked"{/if} /> {lang}wcf.acp.notice.resetIsDismissed{/lang}</label>
+                                               <small>{lang}wcf.acp.notice.resetIsDismissed.description{/lang}</small>
+                                       </dd>
+                               </dl>
+                       {/if}
+                       
+                       {event name='dataFields'}
+               </fieldset>
+               
+               {event name='fieldsets'}
+       </div>
+       
+       <header class="boxHeadline boxSubHeadline">
+               <h2>{lang}wcf.acp.notice.conditions{/lang}</h2>
+               <small>{lang}wcf.acp.notice.conditions.description{/lang}</small>
+       </header>
+       
+       <div class="container containerPadding marginTop">
+               <fieldset>
+                       <legend>{lang}wcf.acp.notice.conditions.page{/lang}</legend>
+                       <small>{lang}wcf.acp.notice.conditions.page.description{/lang}</small>
+                       
+                       {foreach from=$groupedConditionObjectTypes['com.woltlab.wcf.page'] item='pageConditionObjectType'}
+                               {@$pageConditionObjectType->getProcessor()->getHtml()}
+                       {/foreach}
+               </fieldset>
+       </div>
+       
+       <header class="boxHeadline boxSubHeadline">
+               <h2>{lang}wcf.acp.notice.conditions.user{/lang}</h2>
+               <small>{lang}wcf.acp.notice.conditions.user.description{/lang}</small>
+       </header>
+       
+       {include file='userConditions' groupedObjectTypes=$groupedConditionObjectTypes['com.woltlab.wcf.user']}
+       
+       <div class="formSubmit">
+               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+               {@SECURITY_TOKEN_INPUT_TAG}
+       </div>
+</form>
+
+{include file='footer'}
diff --git a/wcfsetup/install/files/acp/templates/noticeList.tpl b/wcfsetup/install/files/acp/templates/noticeList.tpl
new file mode 100644 (file)
index 0000000..60bcb6a
--- /dev/null
@@ -0,0 +1,69 @@
+{include file='header' pageTitle='wcf.acp.notice.list'}
+
+<script data-relocate="true">
+       //<![CDATA[
+       $(function() {
+               new WCF.Action.Delete('wcf\\data\\notice\\NoticeAction', '.jsNotice');
+               new WCF.Action.Toggle('wcf\\data\\notice\\NoticeAction', '.jsNotice');
+               new WCF.Sortable.List('noticeList', 'wcf\\data\\notice\\NoticeAction', {@$startIndex});
+       });
+       //]]>
+</script>
+
+<header class="boxHeadline">
+       <h1>{lang}wcf.acp.notice.list{/lang}</h1>
+</header>
+
+<div class="contentNavigation">
+       {pages print=true assign=pagesLinks controller="NoticeList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}
+       
+       <nav>
+               <ul>
+                       <li><a href="{link controller='NoticeAdd'}{/link}" class="button"><span class="icon icon16 icon-plus"></span> <span>{lang}wcf.acp.menu.link.notice.add{/lang}</span></a></li>
+                       
+                       {event name='contentNavigationButtonsTop'}
+               </ul>
+       </nav>
+</div>
+
+{if $objects|count}
+       <div class="container containerPadding sortableListContainer marginTop"  id="noticeList">
+               <ol class="sortableList" data-object-id="0" start="{@($pageNo - 1) * $itemsPerPage + 1}">
+                       {foreach from=$objects item='notice'}
+                               <li class="sortableNode sortableNoNesting jsNotice" data-object-id="{@$notice->noticeID}">
+                                       <span class="sortableNodeLabel">
+                                               <a href="{link controller='NoticeEdit' object=$notice}{/link}">{$notice->noticeName}</a>
+                                               
+                                               <span class="statusDisplay sortableButtonContainer">
+                                                       <span class="icon icon16 icon-check{if $notice->isDisabled}-empty{/if} jsToggleButton jsTooltip pointer" title="{lang}wcf.global.button.{if $notice->isDisabled}enable{else}disable{/if}{/lang}" data-object-id="{@$notice->noticeID}" data-disable-message="{lang}wcf.global.button.disable{/lang}" data-enable-message="{lang}wcf.global.button.enable{/lang}"></span>
+                                                       <a href="{link controller='NoticeEdit' object=$notice}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 icon-pencil"></span></a>
+                                                       <span class="icon icon16 icon-remove jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$notice->noticeID}" data-confirm-message="{lang}wcf.acp.notice.delete.confirmMessage{/lang}"></span>
+                                                       
+                                                       {event name='itemButtons'}
+                                               </span>
+                                       </span>
+                               </li>
+                       {/foreach}
+               </ol>
+               
+               <div class="formSubmit">
+                       <button class="button" data-type="submit">{lang}wcf.global.button.saveSorting{/lang}</button>
+               </div>
+       </div>
+       
+       <div class="contentNavigation">
+               {@$pagesLinks}
+               
+               <nav>
+                       <ul>
+                               <li><a href="{link controller='NoticeAdd'}{/link}" class="button"><span class="icon icon16 icon-plus"></span> <span>{lang}wcf.acp.menu.link.notice.add{/lang}</span></a></li>
+                               
+                               {event name='contentNavigationButtonsBottom'}
+                       </ul>
+               </nav>
+       </div>
+{else}
+       <p class="info">{lang}wcf.global.noItems{/lang}</p>
+{/if}
+
+{include file='footer'}
index 5a107aaca805faf72b911cd6120718a8603975ac..d73ba015bf8adcf8acc6995d266706a6333642ea 100755 (executable)
@@ -10754,6 +10754,136 @@ WCF.Category.NestedList = Class.extend({
        }
 });
 
+/**
+ * Initializes WCF.Condition namespace.
+ */
+WCF.Condition = { };
+
+/**
+ * Handles displaying the a form element whose visibility depends on the selected
+ * page controllers.
+ */
+WCF.Condition.PageControllerDependence = Class.extend({
+       /**
+        * select list with the available page controllers
+        * @var jQuery
+        */
+       _pageControllerSelection: null,
+       
+       /**
+        * ids of page object types that support the form element
+        * @var array<integer>
+        */
+       _supportedPageObjectTypeIDs: [],
+       
+       /**
+        * Initializes a new WCF.Condition.PageControllerDependence object.
+        * 
+        * @param       string                  inputIdentifier
+        * @param       array<integer>          supportedPageObjectTypeIDs
+        */
+       init: function(inputIdentifier, supportedPageObjectTypeIDs) {
+               this._supportedPageObjectTypeIDs = supportedPageObjectTypeIDs;
+               
+               this._pageControllerSelection = $('#pageControllers').change($.proxy(this._checkVisibility, this));
+               this._pageControllerContainer = this._pageControllerSelection.parents('dl:eq(0)');
+               
+               this._input = $('#' + inputIdentifier);
+               this._inputContainer = this._input.parents('dl:eq(0)');
+               
+               this._checkVisibility();
+       },
+       
+       /**
+        * Checks the visibility based on the selected page controllers.
+        */
+       _checkVisibility: function() {
+               var $selectedPageIDs = this._pageControllerSelection.val() || [ ];
+               
+               var $display = true;
+               if ($selectedPageIDs.length) {
+                       for (var $i = 0, $length = $selectedPageIDs.length; $i < $length; $i++) {
+                               if (this._supportedPageObjectTypeIDs.indexOf(parseInt($selectedPageIDs[$i])) == -1) {
+                                       $display = false;
+                                       break;
+                               }
+                       }
+               }
+               else {
+                       $display = false;
+               }
+               
+               if ($display) {
+                       this._inputContainer.show();
+                       this._input.enable();
+               }
+               else {
+                       this._inputContainer.hide();
+                       this._input.disable();
+               }
+       }
+});
+
+/**
+ * Initialize WCF.Notice namespace.
+ */
+WCF.Notice = { };
+
+/**
+ * Handles dismissing notices.
+ */
+WCF.Notice.Dismiss = Class.extend({
+       /**
+        * list with notices
+        * @var jQuery
+        */
+       _notices: { },
+       
+       /**
+        * action proxy object
+        * @var WCF.Action.Proxy
+        */
+       _proxy: null,
+       
+       /**
+        * Initializes a new WCF.Notice.Dismiss object.
+        */
+       init: function() {
+               this._proxy = new WCF.Action.Proxy({
+                       success: $.proxy(this._success, this)
+               });
+               
+               var $dismissButtons = $('.jsDismissNoticeButton').click($.proxy(this._click, this));
+               
+               $dismissButtons.each($.proxy(function(index, element) {
+                       this._notices[$(element).data('objectID')] = $(element).parent();
+               }, this));
+       },
+       
+       /**
+        * Handles clicking on 
+        */
+       _click: function(event) {
+               this._proxy.setOption('data', {
+                       actionName: 'dismiss',
+                       className: 'wcf\\data\\notice\\NoticeAction',
+                       objectIDs: [ $(event.currentTarget).data('objectID') ]
+               });
+               this._proxy.sendRequest();
+       },
+       
+       /**
+        * Handles successfull AJAX request.
+        * 
+        * @param       object          data
+        * @param       string          textStatus
+        * @param       jQuery          jqXHR
+        */
+       _success: function(data, textStatus, jqXHR) {
+               this._notices[data.returnValues.noticeID].wcfFadeOut();
+       }
+});
+
 /**
  * Encapsulate eval() within an own function to prevent problems
  * with optimizing and minifiny JS.
diff --git a/wcfsetup/install/files/lib/acp/form/NoticeAddForm.class.php b/wcfsetup/install/files/lib/acp/form/NoticeAddForm.class.php
new file mode 100644 (file)
index 0000000..f394ec3
--- /dev/null
@@ -0,0 +1,245 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\object\type\ObjectTypeCache;
+use wcf\data\notice\NoticeAction;
+use wcf\data\notice\NoticeEditor;
+use wcf\form\AbstractForm;
+use wcf\system\condition\ConditionHandler;
+use wcf\system\exception\UserInputException;
+use wcf\system\language\I18nHandler;
+use wcf\system\WCF;
+use wcf\util\StringUtil;
+
+/**
+ * Shows the form to create a new notice.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class NoticeAddForm extends AbstractForm {
+       /**
+        * @see \wcf\page\AbstractPage::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.notice.add';
+       
+       /**
+        * grouped notice condition object types
+        * @var array
+        */
+       public $groupedConditionObjectTypes = array();
+       
+       /**
+        * 1 if the notice is disabled
+        * @var integer
+        */
+       public $isDisabled = 0;
+       
+       /**
+        * 1 if the notice is dismissible
+        * @var integer
+        */
+       public $isDismissible = 0;
+       
+       /**
+        * @see \wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.content.notice.canManageNotice');
+       
+       /**
+        * name of the notice
+        * @var string
+        */
+       public $noticeName = '';
+       
+       /**
+        * 1 if html is used in the notice text
+        * @var integer
+        */
+       public $noticeUseHtml = 0;
+       
+       /**
+        * order used to the show the notices
+        * @var integer
+        */
+       public $showOrder = 0;
+       
+       /**
+        * @see \wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               I18nHandler::getInstance()->assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'action' => 'add',
+                       'isDisabled' => $this->isDisabled,
+                       'isDismissible' => $this->isDismissible,
+                       'groupedConditionObjectTypes' => $this->groupedConditionObjectTypes,
+                       'noticeName' => $this->noticeName,
+                       'noticeUseHtml' => $this->noticeUseHtml,
+                       'showOrder' => $this->showOrder
+               ));
+       }
+       
+       /**
+        * @see \wcf\page\IPage::readData()
+        */
+       public function readData() {
+               $objectTypes = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.condition.notice');
+               foreach ($objectTypes as $objectType) {
+                       if (!$objectType->conditionobject) continue;
+                       
+                       if (!isset($this->groupedConditionObjectTypes[$objectType->conditionobject])) {
+                               $this->groupedConditionObjectTypes[$objectType->conditionobject] = array();
+                       }
+                       
+                       if ($objectType->conditiongroup) {
+                               if (!isset($this->groupedConditionObjectTypes[$objectType->conditionobject][$objectType->conditiongroup])) {
+                                       $this->groupedConditionObjectTypes[$objectType->conditionobject][$objectType->conditiongroup] = array();
+                               }
+                               
+                               $this->groupedConditionObjectTypes[$objectType->conditionobject][$objectType->conditiongroup][$objectType->objectTypeID] = $objectType;
+                       }
+                       else {
+                               $this->groupedConditionObjectTypes[$objectType->conditionobject][$objectType->objectTypeID] = $objectType;
+                       }
+               }
+               
+               parent::readData();
+       }
+       
+       /**
+        * @see \wcf\form\IForm::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               I18nHandler::getInstance()->readValues();
+               
+               if (isset($_POST['isDisabled'])) $this->isDisabled = 1;
+               if (isset($_POST['isDismissible'])) $this->isDismissible = 1;
+               if (isset($_POST['noticeName'])) $this->noticeName = StringUtil::trim($_POST['noticeName']);
+               if (isset($_POST['noticeUseHtml'])) $this->noticeUseHtml = 1;
+               if (isset($_POST['showOrder'])) $this->showOrder = intval($_POST['showOrder']);
+               
+               foreach ($this->groupedConditionObjectTypes as $groupedObjectTypes) {
+                       foreach ($groupedObjectTypes as $objectTypes) {
+                               if (is_array($objectTypes)) {
+                                       foreach ($objectTypes as $objectType) {
+                                               $objectType->getProcessor()->readFormParameters();
+                                       }
+                               }
+                               else {
+                                       $objectTypes->getProcessor()->readFormParameters();
+                               }
+                       }
+               }
+       }
+       
+       /**
+        * @see \wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               I18nHandler::getInstance()->register('notice');
+       }
+       
+       /**
+        * @see \wcf\form\IForm::save()
+        */
+       public function save() {
+               parent::save();
+               
+               $this->objectAction = new NoticeAction(array(), 'create', array(
+                       'data' => array(
+                               'isDisabled' => $this->isDisabled,
+                               'isDismissible' => $this->isDismissible,
+                               'notice' => I18nHandler::getInstance()->isPlainValue('notice') ? I18nHandler::getInstance()->getValue('notice') : '',
+                               'noticeName' => $this->noticeName,
+                               'noticeUseHtml' => $this->noticeUseHtml,
+                               'showOrder' => $this->showOrder
+                       )
+               ));
+               $returnValues = $this->objectAction->executeAction();
+               
+               if (!I18nHandler::getInstance()->isPlainValue('notice')) {
+                       I18nHandler::getInstance()->save('notice', 'wcf.notice.notice.notice'.$returnValues['returnValues']->noticeID, 'wcf.notice', 1);
+                       
+                       // update notice name
+                       $noticeEditor = new NoticeEditor($returnValues['returnValues']);
+                       $noticeEditor->update(array(
+                               'notice' => 'wcf.notice.notice.notice'.$returnValues['returnValues']->noticeID
+                       ));
+               }
+               
+               // transform conditions array into one-dimensional array
+               $conditions = array();
+               foreach ($this->groupedConditionObjectTypes as $groupedObjectTypes) {
+                       foreach ($groupedObjectTypes as $objectTypes) {
+                               if (is_array($objectTypes)) {
+                                       $conditions = array_merge($conditions, $objectTypes);
+                               }
+                               else {
+                                       $conditions[] = $objectTypes;
+                               }
+                       }
+               }
+               
+               ConditionHandler::getInstance()->createConditions($returnValues['returnValues']->noticeID, $conditions);
+               
+               $this->saved();
+               
+               // reset values
+               $this->isDisabled = 0;
+               $this->isDismissible = 0;
+               $this->noticeName = '';
+               $this->noticeUseHtml = 0;
+               $this->showOrder = 0;
+               I18nHandler::getInstance()->reset();
+               
+               foreach ($conditions as $condition) {
+                       $condition->getProcessor()->reset();
+               }
+               
+               WCF::getTPL()->assign('success', true);
+       }
+       
+       /**
+        * @see \wcf\form\IForm::validate()
+        */
+       public function validate() {
+               parent::validate();
+               
+               if (empty($this->noticeName)) {
+                       throw new UserInputException('noticeName');
+               }
+               
+               if (!I18nHandler::getInstance()->validateValue('notice')) {
+                       if (I18nHandler::getInstance()->isPlainValue('notice')) {
+                               throw new UserInputException('notice');
+                       }
+                       else {
+                               throw new UserInputException('notice', 'multilingual');
+                       }
+               }
+               
+               foreach ($this->groupedConditionObjectTypes as $groupedObjectTypes) {
+                       foreach ($groupedObjectTypes as $objectTypes) {
+                               if (is_array($objectTypes)) {
+                                       foreach ($objectTypes as $objectType) {
+                                               $objectType->getProcessor()->validate();
+                                       }
+                               }
+                               else {
+                                       $objectTypes->getProcessor()->validate();
+                               }
+                       }
+               }
+       }
+}
diff --git a/wcfsetup/install/files/lib/acp/form/NoticeEditForm.class.php b/wcfsetup/install/files/lib/acp/form/NoticeEditForm.class.php
new file mode 100644 (file)
index 0000000..6fd4a18
--- /dev/null
@@ -0,0 +1,184 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\notice\Notice;
+use wcf\data\notice\NoticeAction;
+use wcf\data\notice\NoticeEditor;
+use wcf\form\AbstractForm;
+use wcf\system\condition\ConditionHandler;
+use wcf\system\language\I18nHandler;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\user\storage\UserStorageHandler;
+use wcf\system\WCF;
+
+/**
+ * Shows the form to edit an existing notice.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class NoticeEditForm extends NoticeAddForm {
+       /**
+        * @see \wcf\page\AbstractPage::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.notice';
+       
+       /**
+        * edited notice object
+        * @var \wcf\data\notice\Notice
+        */
+       public $notice = null;
+       
+       /**
+        * id of the edited notice object
+        * @var integer
+        */
+       public $noticeID = 0;
+       
+       /**
+        * 1 if the notice will be displayed for all users again
+        * @var unknown
+        */
+       public $resetIsDismissed = 0;
+       
+       /**
+        * @see \wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               I18nHandler::getInstance()->assignVariables(!empty($_POST));
+               
+               WCF::getTPL()->assign(array(
+                       'action' => 'edit',
+                       'notice' => $this->notice,
+                       'resetIsDismissed' => $this->resetIsDismissed
+               ));
+       }
+       
+       /**
+        * @see \wcf\page\IPage::readData()
+        */
+       public function readData() {
+               parent::readData();
+               
+               if (empty($_POST)) {
+                       I18nHandler::getInstance()->setOptions('notice', 1, $this->notice->notice, 'wcf.notice.notice.notice\d+');
+                       
+                       $this->isDisabled = $this->notice->isDisabled;
+                       $this->isDismissible = $this->notice->isDismissible;
+                       $this->noticeName = $this->notice->noticeName;
+                       $this->noticeUseHtml = $this->notice->noticeUseHtml;
+                       $this->showOrder = $this->notice->showOrder;
+                       
+                       $conditions = $this->notice->getConditions();
+                       $conditionsByObjectTypeID = array();
+                       foreach ($conditions as $condition) {
+                               $conditionsByObjectTypeID[$condition->objectTypeID] = $condition;
+                       }
+                       
+                       foreach ($this->groupedConditionObjectTypes as $objectTypes1) {
+                               foreach ($objectTypes1 as $objectTypes2) {
+                                       if (is_array($objectTypes2)) {
+                                               foreach ($objectTypes2 as $objectType) {
+                                                       if (isset($conditionsByObjectTypeID[$objectType->objectTypeID])) {
+                                                               $conditionsByObjectTypeID[$objectType->objectTypeID]->getObjectType()->getProcessor()->setData($conditionsByObjectTypeID[$objectType->objectTypeID]);
+                                                       }
+                                               }
+                                       }
+                                       else if (isset($conditionsByObjectTypeID[$objectTypes2->objectTypeID])) {
+                                               $conditionsByObjectTypeID[$objectTypes2->objectTypeID]->getObjectType()->getProcessor()->setData($conditionsByObjectTypeID[$objectTypes2->objectTypeID]);
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       /**
+        * @see \wcf\form\IForm::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               if (isset($_POST['resetIsDismissed'])) $this->resetIsDismissed = 1;
+       }
+       
+       /**
+        * @see \wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               if (isset($_REQUEST['id'])) $this->noticeID = intval($_REQUEST['id']);
+               $this->notice = new Notice($this->noticeID);
+               if (!$this->notice->noticeID) {
+                       throw new IllegalLinkException();
+               }
+       }
+       
+       /**
+        * @see \wcf\form\IForm::save()
+        */
+       public function save() {
+               AbstractForm::save();
+               
+               $this->objectAction = new NoticeAction(array($this->notice), 'update', array(
+                       'data' => array(
+                               'isDisabled' => $this->isDisabled,
+                               'isDismissible' => $this->isDismissible,
+                               'notice' => I18nHandler::getInstance()->isPlainValue('notice') ? I18nHandler::getInstance()->getValue('notice') : 'wcf.notice.notice.notice'.$this->notice->noticeID,
+                               'noticeName' => $this->noticeName,
+                               'noticeUseHtml' => $this->noticeUseHtml,
+                               'showOrder' => $this->showOrder
+                       )
+               ));
+               $this->objectAction->executeAction();
+               
+               if (I18nHandler::getInstance()->isPlainValue('notice')) {
+                       if ($this->notice->notice == 'wcf.notice.notice.notice'.$this->notice->noticeID) {
+                               I18nHandler::getInstance()->remove($this->notice->notice);
+                       }
+               }
+               else {
+                       I18nHandler::getInstance()->save('notice', 'wcf.notice.notice.notice'.$this->notice->noticeID, 'wcf.notice', 1);
+               }
+               
+               // transform conditions array into one-dimensional array
+               $conditions = array();
+               foreach ($this->groupedConditionObjectTypes as $groupedObjectTypes) {
+                       foreach ($groupedObjectTypes as $objectTypes) {
+                               if (is_array($objectTypes)) {
+                                       $conditions = array_merge($conditions, $objectTypes);
+                               }
+                               else {
+                                       $conditions[] = $objectTypes;
+                               }
+                       }
+               }
+               
+               ConditionHandler::getInstance()->updateConditions($this->notice->noticeID, $this->notice->getConditions(), $conditions);
+               
+               if ($this->resetIsDismissed) {
+                       $sql = "DELETE FROM     wcf".WCF_N."_notice_dismissed
+                               WHERE           noticeID = ?";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute(array(
+                               $this->notice->noticeID
+                       ));
+                       
+                       $this->resetIsDismissed = 0;
+                       
+                       UserStorageHandler::getInstance()->resetAll('dismissedNotices');
+               }
+               
+               $this->saved();
+               
+               // reload notice object for proper 'isDismissible' value
+               $this->notice = new Notice($this->noticeID);
+               
+               WCF::getTPL()->assign('success', true);
+       }
+}
index 6897fda9143da0e3a40ba34c799f527159748513..45eeed64aa14e32adfc73ffabbf0468de0b8c7f2 100644 (file)
@@ -128,7 +128,13 @@ class UserGroupAssignmentAddForm extends AbstractForm {
                ));
                $returnValues = $this->objectAction->executeAction();
                
-               ConditionHandler::getInstance()->createConditions($returnValues['returnValues']->assignmentID, $this->conditions);
+               // transform conditions array into one-dimensional array
+               $conditions = array();
+               foreach ($this->conditions as $groupedObjectTypes) {
+                       $conditions = array_merge($conditions, $groupedObjectTypes);
+               }
+               
+               ConditionHandler::getInstance()->createConditions($returnValues['returnValues']->assignmentID, $conditions);
                
                $this->saved();
                
index 9e5fa51675138e0c9b44d95f1aa0c857a8e4c023..939ef6a82cae2c12177c961a8ab217cc5f02c507 100644 (file)
@@ -87,7 +87,13 @@ class UserGroupAssignmentEditForm extends UserGroupAssignmentAddForm {
                ));
                $returnValues = $this->objectAction->executeAction();
                
-               ConditionHandler::getInstance()->updateConditions($this->assignment->assignmentID, $this->assignment->getConditions(), $this->conditions);
+               // transform conditions array into one-dimensional array
+               $conditions = array();
+               foreach ($this->conditions as $groupedObjectTypes) {
+                       $conditions = array_merge($conditions, $groupedObjectTypes);
+               }
+               
+               ConditionHandler::getInstance()->updateConditions($this->assignment->assignmentID, $this->assignment->getConditions(), $conditions);
                
                $this->saved();
                
diff --git a/wcfsetup/install/files/lib/acp/page/NoticeListPage.class.php b/wcfsetup/install/files/lib/acp/page/NoticeListPage.class.php
new file mode 100644 (file)
index 0000000..11dde8b
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+namespace wcf\acp\page;
+use wcf\page\SortablePage;
+
+/**
+ * Lists the available notices.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.page
+ * @category   Community Framework
+ */
+class NoticeListPage extends SortablePage {
+       /**
+        * @see \wcf\page\AbstractPage::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.notice.list';
+       
+       /**
+        * @see \wcf\page\SortablePage::$defaultSortField
+        */
+       public $defaultSortField = 'showOrder';
+       
+       /**
+        * @see \wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.content.notice.canManageNotice');
+       
+       /**
+        * @see \wcf\page\MultipleLinkPage::$objectListClassName
+        */
+       public $objectListClassName = 'wcf\data\notice\NoticeList';
+       
+       /**
+        * @see \wcf\page\SortablePage::$objectListClassName
+        */
+       public $validSortFields = array('noticeID', 'noticeName', 'showOrder');
+}
diff --git a/wcfsetup/install/files/lib/data/notice/Notice.class.php b/wcfsetup/install/files/lib/data/notice/Notice.class.php
new file mode 100644 (file)
index 0000000..8e4f7cf
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+namespace wcf\data\notice;
+use wcf\data\DatabaseObject;
+use wcf\system\condition\ConditionHandler;
+use wcf\system\request\IRouteController;
+use wcf\system\user\storage\UserStorageHandler;
+use wcf\system\WCF;
+
+/**
+ * Represents a notice.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.notice
+ * @category   Community Framework
+ */
+class Notice extends DatabaseObject implements IRouteController {
+       /**
+        * true if the active user has dismissed the notice
+        * @var boolean
+        */
+       protected $isDismissed = null;
+       
+       /**
+        * @see \wcf\data\DatabaseObject::$databaseTableName
+        */
+       protected static $databaseTableName = 'notice';
+       
+       /**
+        * @see \wcf\data\DatabaseObject::$databaseIndexName
+        */
+       protected static $databaseTableIndexName = 'noticeID';
+       
+       /**
+        * Returns the conditions of the notice.
+        * 
+        * @return      array<\wcf\data\condition\Condition>
+        */
+       public function getConditions() {
+               return ConditionHandler::getInstance()->getConditions('com.woltlab.wcf.condition.notice', $this->noticeID);
+       }
+       
+       /**
+        * @see \wcf\data\ITitledObject::getTitle()
+        */
+       public function getTitle() {
+               return $this->noticeName;
+       }
+       
+       /**
+        * Returns true if the active user has dismissed the notice.
+        * 
+        * @return      boolean
+        */
+       public function isDismissed() {
+               if (!$this->isDismissible) return false;
+               
+               if ($this->isDismissed === null) {
+                       if (WCF::getUser()->userID) {
+                               UserStorageHandler::getInstance()->loadStorage(array(WCF::getUser()->userID));
+                               $dismissedNotices = UserStorageHandler::getInstance()->getStorage(array(WCF::getUser()->userID), 'dismissedNotices');
+                               if ($dismissedNotices[WCF::getUser()->userID] === null) {
+                                       $sql = "SELECT  noticeID
+                                               FROM    wcf".WCF_N."_notice_dismissed
+                                               WHERE   userID = ?";
+                                       $statement = WCF::getDB()->prepareStatement($sql);
+                                       $statement->execute(array(
+                                               WCF::getUser()->userID
+                                       ));
+                                       
+                                       $noticeIDs = array();
+                                       while ($noticeID = $statement->fetchColumn()) {
+                                               $noticeIDs[] = $noticeID;
+                                               
+                                               if ($noticeID == $this->noticeID) {
+                                                       $this->isDismissed = true;
+                                               }
+                                       }
+                                       
+                                       UserStorageHandler::getInstance()->update(WCF::getUser()->userID, 'dismissedNotices', serialize($noticeIDs));
+                               }
+                               else {
+                                       $dismissedNoticeIDs = @unserialize($dismissedNotices[WCF::getUser()->userID]);
+                                       $this->isDismissed = isset($dismissedNoticeIDs[$this->noticeID]);
+                               }
+                       }
+                       else {
+                               $dismissedNotices = WCF::getSession()->getVar('dismissedNotices');
+                               if ($dismissedNotices !== null) {
+                                       $dismissedNotices = @unserialize($dismissedNotices);
+                                       $this->isDismissed = in_array($this->noticeID, $dismissedNotices);
+                               }
+                               else {
+                                       $this->isDismissed = false;
+                               }
+                       }
+               }
+               
+               return $this->isDismissed;
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/notice/NoticeAction.class.php b/wcfsetup/install/files/lib/data/notice/NoticeAction.class.php
new file mode 100644 (file)
index 0000000..21a2ac1
--- /dev/null
@@ -0,0 +1,170 @@
+<?php
+namespace wcf\data\notice;
+use wcf\data\AbstractDatabaseObjectAction;
+use wcf\data\ISortableAction;
+use wcf\data\IToggleAction;
+use wcf\system\exception\UserInputException;
+use wcf\system\user\storage\UserStorageHandler;
+use wcf\system\WCF;
+
+/**
+ * Executes notice-related actions.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.notice
+ * @category   Community Framework
+ */
+class NoticeAction extends AbstractDatabaseObjectAction implements ISortableAction, IToggleAction {
+       /**
+        * @see \wcf\data\AbstractDatabaseObjectAction::$allowGuestAccess
+        */
+       protected $allowGuestAccess = array('dismiss');
+       
+       /**
+        * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
+        */
+       protected $permissionsDelete = array('admin.content.notice.canManageNotice');
+       
+       /**
+        * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
+        */
+       protected $permissionsUpdate = array('admin.content.notice.canManageNotice');
+       
+       /**
+        * @see \wcf\data\AbstractDatabaseObjectAction::$requireACP
+        */
+       protected $requireACP = array('create', 'delete', 'toggle', 'update', 'updatePosition');
+       
+       /**
+        * @see \wcf\data\AbstractDatabaseObjectAction::create()
+        */
+       public function create() {
+               $showOrder = 0;
+               if (isset($this->parameters['data']['showOrder'])) {
+                       $showOrder = $this->parameters['data']['showOrder'];
+                       unset($this->parameters['data']['showOrder']);
+               }
+               
+               $notice = parent::create();
+               $noticeEditor = new NoticeEditor($notice);
+               $noticeEditor->setShowOrder($showOrder);
+               
+               return new Notice($notice->noticeID);
+       }
+       
+       /**
+        * Dismisses a certain notice.
+        * 
+        * @return      array<integer>
+        */
+       public function dismiss() {
+               if (WCF::getUser()->userID) {
+                       $sql = "INSERT INTO     wcf".WCF_N."_notice_dismissed
+                                               (noticeID, userID)
+                               VALUES          (?, ?)";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute(array(
+                               reset($this->objectIDs),
+                               WCF::getUser()->userID
+                       ));
+                       
+                       UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'dismissedNotices');
+               }
+               else {
+                       $dismissedNotices = WCF::getSession()->getVar('dismissedNotices');
+                       if ($dismissedNotices !== null) {
+                               $dismissedNotices = @unserialize($dismissedNotices);
+                               $dismissedNotices[] = reset($this->objectIDs);
+                       }
+                       else {
+                               $dismissedNotices = array(
+                                       reset($this->objectIDs)
+                               );
+                       }
+                       
+                       WCF::getSession()->register('dismissedNotices', serialize($dismissedNotices));
+               }
+               
+               return array(
+                       'noticeID' => reset($this->objectIDs)
+               );
+       }
+       
+       /**
+        * @see \wcf\data\IToggleAction::toggle()
+        */
+       public function toggle() {
+               foreach ($this->objects as $notice) {
+                       $notice->update(array(
+                               'isDisabled' => $notice->isDisabled ? 0 : 1
+                       ));
+               }
+       }
+       
+       /**
+        * Validates the 'dismiss' action.
+        */
+       public function validateDismiss() {
+               $this->getSingleObject();
+       }
+       
+       /**
+        * @see \wcf\data\IToggleAction::validateToggle()
+        */
+       public function validateToggle() {
+               parent::validateUpdate();
+       }
+       
+       /**
+        * @see \wcf\data\ISortableAction::validateUpdatePosition()
+        */
+       public function validateUpdatePosition() {
+               WCF::getSession()->checkPermissions($this->permissionsUpdate);
+               
+               if (!isset($this->parameters['data']['structure']) || !is_array($this->parameters['data']['structure'])) {
+                       throw new UserInputException('structure');
+               }
+               
+               $noticeList = new NoticeList();
+               $noticeList->getConditionBuilder()->add('notice.noticeID IN (?)', array($this->parameters['data']['structure'][0]));
+               if ($noticeList->countObjects() != count($this->parameters['data']['structure'][0])) {
+                       throw new UserInputException('structure');
+               }
+               
+               $this->readInteger('offset', true, 'data');
+       }
+       
+       /**
+        * @see \wcf\data\AbstractDatabaseObjectAction::update()
+        */
+       public function update() {
+               parent::update();
+               
+               if (count($this->objects) == 1 && isset($this->parameters['data']['showOrder']) && $this->parameters['data']['showOrder'] != reset($this->objects)->showOrder) {
+                       reset($this->objects)->setShowOrder($this->parameters['data']['showOrder']);
+               }
+       }
+       
+       /**
+        * @see \wcf\data\ISortableAction::updatePosition()
+        */
+       public function updatePosition() {
+               $sql = "UPDATE  wcf".WCF_N."_notice
+                       SET     showOrder = ?
+                       WHERE   noticeID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               
+               $showOrder = $this->parameters['data']['offset'];
+               WCF::getDB()->beginTransaction();
+               foreach ($this->parameters['data']['structure'][0] as $noticeID) {
+                       $statement->execute(array(
+                               $showOrder++,
+                               $noticeID
+                       ));
+               }
+               WCF::getDB()->commitTransaction();
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/notice/NoticeEditor.class.php b/wcfsetup/install/files/lib/data/notice/NoticeEditor.class.php
new file mode 100644 (file)
index 0000000..1c3944f
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+namespace wcf\data\notice;
+use wcf\data\object\type\ObjectTypeCache;
+use wcf\data\DatabaseObjectEditor;
+use wcf\data\IEditableCachedObject;
+use wcf\system\cache\builder\ConditionCacheBuilder;
+use wcf\system\cache\builder\NoticeCacheBuilder;
+use wcf\system\WCF;
+
+/**
+ * Provides functions to edit notices.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.notice
+ * @category   Community Framework
+ */
+class NoticeEditor extends DatabaseObjectEditor implements IEditableCachedObject {
+       /**
+        * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+        */
+       protected static $baseClass = 'wcf\data\notice\Notice';
+       
+       /**
+        * Sets the show order of the notice.
+        * 
+        * @param       integer         $showOrder
+        */
+       public function setShowOrder($showOrder = 0) {
+               $newShowOrder = 1;
+               
+               $sql = "SELECT  MAX(showOrder)
+                       FROM    wcf".WCF_N."_notice";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute();
+               $maxShowOrder = $statement->fetchColumn();
+               if (!$maxShowOrder) $maxShowOrder = 0;
+               
+               if (!$showOrder || $showOrder > $maxShowOrder) {
+                       $newShowOrder = $maxShowOrder + 1;
+               }
+               else {
+                       // shift other notices
+                       $sql = "UPDATE  wcf".WCF_N."_notice
+                               SET     showOrder = showOrder + 1
+                               WHERE   showOrder >= ?";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute(array(
+                               $showOrder
+                       ));
+                       
+                       $newShowOrder = $showOrder;
+               }
+               
+               $this->update(array(
+                       'showOrder' => $newShowOrder
+               ));
+       }
+       
+       /**
+        * @see \wcf\data\IEditableCachedObject::resetCache()
+        */
+       public static function resetCache() {
+               NoticeCacheBuilder::getInstance()->reset();
+               ConditionCacheBuilder::getInstance()->reset(array(
+                       'definitionID' => ObjectTypeCache::getInstance()->getDefinitionByName('com.woltlab.wcf.condition.notice')->definitionID
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/notice/NoticeList.class.php b/wcfsetup/install/files/lib/data/notice/NoticeList.class.php
new file mode 100644 (file)
index 0000000..6eeac4f
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+namespace wcf\data\notice;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of notices.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.notice
+ * @category   Community Framework
+ */
+class NoticeList extends DatabaseObjectList { }
diff --git a/wcfsetup/install/files/lib/system/cache/builder/NoticeCacheBuilder.class.php b/wcfsetup/install/files/lib/system/cache/builder/NoticeCacheBuilder.class.php
new file mode 100644 (file)
index 0000000..20bc0e5
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+namespace wcf\system\cache\builder;
+use wcf\data\notice\NoticeList;
+
+/**
+ * Caches the enabled notices.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.cache.builder
+ * @category   Community Framework
+ */
+class NoticeCacheBuilder extends AbstractCacheBuilder {
+       /**
+        * @see \wcf\system\cache\builder\AbstractCacheBuilder::rebuild()
+        */
+       protected function rebuild(array $parameters) {
+               $noticeList = new NoticeList();
+               $noticeList->getConditionBuilder()->add('isDisabled = ?', array(0));
+               $noticeList->sqlOrderBy = 'showOrder ASC';
+               $noticeList->readObjects();
+               
+               return $noticeList->getObjects();
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/condition/AbstractMultiSelectCondition.class.php b/wcfsetup/install/files/lib/system/condition/AbstractMultiSelectCondition.class.php
new file mode 100644 (file)
index 0000000..3910e4d
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+namespace wcf\system\condition;
+use wcf\data\condition\Condition;
+use wcf\system\exception\UserInputException;
+use wcf\system\WCF;
+use wcf\util\ArrayUtil;
+
+/**
+ * Abstract implementation of a condition with multi select options.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.condition
+ * @category   Community Framework
+ */
+abstract class AbstractMultiSelectCondition extends AbstractSelectCondition {
+       /**
+        * @see \wcf\system\condition\AbstractSelectCondition::$fieldValue
+        */
+       protected $fieldValue = array();
+       
+       /**
+        * @see \wcf\system\condition\ICondition::getData()
+        */
+       public function getData() {
+               if (!empty($this->fieldValue)) {
+                       return array(
+                               $this->fieldName => $this->fieldValue
+                       );
+               }
+               
+               return null;
+       }
+       
+       /**
+        * @see \wcf\system\condition\AbstractSingleFieldCondition::getFieldElement()
+        */
+       protected function getFieldElement() {
+               $options = $this->getOptions();
+               
+               $fieldElement = '<select name="'.$this->fieldName.'[]" id="'.$this->fieldName.'" multiple="multiple" size="'.(count($options) > 10 ? 10 : count($options)).'">';
+               foreach ($options as $value => $label) {
+                       $fieldElement .= '<option value="'.$value.'"'.(in_array($value, $this->fieldValue) ? ' selected="selected"' : '').'>'.WCF::getLanguage()->get($label).'</option>';
+               }
+               $fieldElement .= "</select>";
+               
+               return $fieldElement;
+       }
+       
+       /**
+        * @see \wcf\system\condition\ICondition::readFormParameters()
+        */
+       public function readFormParameters() {
+               if (isset($_POST[$this->fieldName]) && is_array($_POST[$this->fieldName])) $this->fieldValue = ArrayUtil::toIntegerArray($_POST[$this->fieldName]);
+       }
+       
+       /**
+        * @see \wcf\system\condition\ICondition::validate()
+        */
+       public function reset() {
+               $this->fieldValue = array();
+       }
+       
+       /**
+        * @see \wcf\system\condition\ICondition::validate()
+        */
+       public function validate() {
+               $options = $this->getOptions();
+               foreach ($this->fieldValue as $value) {
+                       if (!isset($options[$value])) {
+                               $this->errorMessage = 'wcf.global.form.error.noValidSelection';
+                               
+                               throw new UserInputException($this->fieldName, 'noValidSelection');
+                       }
+               }
+       }
+}
index 2651641ad1ca4b0d617971e689a0dfea519dc2b8..edda4c856b7a886b88ae2c0f9a344207e684a355 100644 (file)
@@ -28,23 +28,21 @@ class ConditionHandler extends SingletonFactory {
         * Creates condition objects for the object with the given id and based
         * on the given condition object types.
         * 
-        * @param       integer         $objectID
-        * @param       array           $conditionObjectTypes
+        * @param       integer                                         $objectID
+        * @param       array<\wcf\data\object\type\ObjectType>         $conditionObjectTypes
         */
        public function createConditions($objectID, array $conditionObjectTypes) {
-               foreach ($conditionObjectTypes as $objectTypes) {
-                       foreach ($objectTypes as $objectType) {
-                               $conditionData = $objectType->getProcessor()->getData();
-                               if ($conditionData !== null) {
-                                       $conditionAction = new ConditionAction(array(), 'create', array(
-                                               'data' => array(
-                                                       'conditionData' => serialize($conditionData),
-                                                       'objectID' => $objectID,
-                                                       'objectTypeID' => $objectType->objectTypeID
-                                               )
-                                       ));
-                                       $conditionAction->executeAction();
-                               }
+               foreach ($conditionObjectTypes as $objectType) {
+                       $conditionData = $objectType->getProcessor()->getData();
+                       if ($conditionData !== null) {
+                               $conditionAction = new ConditionAction(array(), 'create', array(
+                                       'data' => array(
+                                               'conditionData' => serialize($conditionData),
+                                               'objectID' => $objectID,
+                                               'objectTypeID' => $objectType->objectTypeID
+                                       )
+                               ));
+                               $conditionAction->executeAction();
                        }
                }
        }
@@ -74,7 +72,7 @@ class ConditionHandler extends SingletonFactory {
                        return $this->conditions[$definition->definitionID][$objectID];
                }
                
-               return null;
+               return array();
        }
        
        /**
@@ -82,7 +80,7 @@ class ConditionHandler extends SingletonFactory {
         * 
         * @param       integer                                         $objectID
         * @param       array<\wcf\data\condition\Condition>            $oldConditions
-        * @param       array                                           $conditionObjectTypes
+        * @param       array<\wcf\data\object\type\ObjectType>         $conditionObjectTypes
         */
        public function updateConditions($objectID, array $oldConditions, array $conditionObjectTypes) {
                // delete old conditions first
diff --git a/wcfsetup/install/files/lib/system/condition/INoticeCondition.class.php b/wcfsetup/install/files/lib/system/condition/INoticeCondition.class.php
new file mode 100644 (file)
index 0000000..05f90ca
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+namespace wcf\system\condition;
+use wcf\data\condition\Condition;
+
+/**
+ * Every implementation for notice conditions needs to implements this interface.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.condition
+ * @category   Community Framework
+ */
+interface INoticeCondition extends ICondition {
+       /**
+        * Returns true if a notice with the given condition will be shown.
+        * 
+        * All necessary data to check the condition needs to be globally available
+        * like the active user object via WCF::getUser().
+        * 
+        * @param       \wcf\data\condition\Condition   $condition
+        * @return      boolean
+        */
+       public function showNotice(Condition $condition);
+}
diff --git a/wcfsetup/install/files/lib/system/condition/MultiPageControllerCondition.class.php b/wcfsetup/install/files/lib/system/condition/MultiPageControllerCondition.class.php
new file mode 100644 (file)
index 0000000..1abce2a
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+namespace wcf\system\condition;
+use wcf\data\condition\Condition;
+use wcf\data\object\type\ObjectTypeCache;
+use wcf\system\page\PageManager;
+use wcf\system\request\RequestHandler;
+
+/**
+ * Condition implementation for selecting multiple page controllers.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.condition
+ * @category   Community Framework
+ */
+class MultiPageControllerCondition extends AbstractMultiSelectCondition implements INoticeCondition {
+       /**
+        * @see \wcf\system\condition\AbstractSingleFieldCondition::$label
+        */
+       protected $description = 'wcf.global.multiSelect';
+       
+       /**
+        * @see \wcf\system\condition\AbstractSelectCondition::$fieldName
+        */
+       protected $fieldName = 'pageControllers';
+       
+       /**
+        * @see \wcf\system\condition\AbstractSingleFieldCondition::$label
+        */
+       protected $label = 'wcf.page.requestedPage';
+       
+       /**
+        * @see \wcf\system\condition\AbstractSelectCondition::getOptions()
+        */
+       protected function getOptions() {
+               return PageManager::getInstance()->getSelection();
+       }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               $requestClassName = RequestHandler::getInstance()->getActiveRequest()->getClassName();
+               $pageControllers = $condition->pageControllers;
+               foreach ($pageControllers as $objectTypeID) {
+                       $objectType = ObjectTypeCache::getInstance()->getObjectType($objectTypeID);
+                       if ($objectType === null) return false;
+                       
+                       if ($requestClassName == $objectType->className) {
+                               return true;
+                       }
+               }
+               
+               return false;
+       }
+}
index 26eb24925b717215cd09d608c6c7f0a3f6b2fdb5..0d4170a5478a8ce4055d0faf331dcc1ef601c4d0 100644 (file)
@@ -16,7 +16,7 @@ use wcf\system\WCF;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserAvatarCondition extends AbstractSelectCondition implements IUserCondition {
+class UserAvatarCondition extends AbstractSelectCondition implements INoticeCondition, IUserCondition {
        /**
         * @see wcf\system\condition\AbstractSelectCondition::$fieldName
         */
@@ -94,4 +94,13 @@ class UserAvatarCondition extends AbstractSelectCondition implements IUserCondit
                        self::GRAVATAR => 'wcf.user.condition.avatar.gravatar'
                );
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               if (!WCF::getUser()->userID) return;
+               
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index f6bf199872ee474c2b21971376bf578b6726bc3f..f441422e67f04b2c52f9a7a9a8942159850de4a9 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\system\condition;
 use wcf\data\condition\Condition;
 use wcf\data\user\User;
 use wcf\data\user\UserList;
+use wcf\system\WCF;
 
 /**
  * Condition implementation for the email address of a user.
@@ -14,7 +15,7 @@ use wcf\data\user\UserList;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserEmailCondition extends AbstractTextCondition implements IUserCondition {
+class UserEmailCondition extends AbstractTextCondition implements INoticeCondition, IUserCondition {
        /**
         * @see \wcf\system\condition\AbstractTextCondition::$fieldName
         */
@@ -38,4 +39,13 @@ class UserEmailCondition extends AbstractTextCondition implements IUserCondition
        public function checkUser(Condition $condition, User $user) {
                return mb_strpos($user->email, $condition->email) !== false;
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               if (!WCF::getUser()->userID) return;
+               
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index 4cb3a0e2380eb8540ff0d7e82ce8199854d1b198..c41b249df283c53741cc890abbc4d2f1242762b7 100644 (file)
@@ -5,6 +5,7 @@ use wcf\data\user\group\UserGroup;
 use wcf\data\user\User;
 use wcf\data\user\UserList;
 use wcf\system\exception\UserInputException;
+use wcf\system\WCF;
 use wcf\util\ArrayUtil;
 
 /**
@@ -18,7 +19,7 @@ use wcf\util\ArrayUtil;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserGroupCondition extends AbstractMultipleFieldsCondition implements IUserCondition {
+class UserGroupCondition extends AbstractMultipleFieldsCondition implements INoticeCondition, IUserCondition {
        /**
         * @see \wcf\system\condition\AbstractMultipleFieldsCondition::$descriptions
         */
@@ -70,11 +71,11 @@ class UserGroupCondition extends AbstractMultipleFieldsCondition implements IUse
         */
        public function checkUser(Condition $condition, User $user) {
                $groupIDs = $user->getGroupIDs();
-               if (!empty($condition->groupIDs) && count(array_diff($condition->groupIDs, $groupIDs))) {
+               if (!empty($condition->conditionData['groupIDs']) && count(array_diff($condition->conditionData['groupIDs'], $groupIDs))) {
                        return false;
                }
                
-               if (!empty($condition->notGroupIDs) && count(array_intersect($condition->notGroupIDs, $groupIDs))) {
+               if (!empty($condition->conditionData['notGroupIDs']) && count(array_intersect($condition->conditionData['notGroupIDs'], $groupIDs))) {
                        return false;
                }
                
@@ -149,7 +150,12 @@ HTML;
         */
        protected function getUserGroups() {
                if ($this->userGroups == null) {
-                       $this->userGroups = UserGroup::getGroupsByType(array(UserGroup::OTHER));
+                       $groupTypes = array(UserGroup::OTHER);
+                       if ($this->includeguests) {
+                               $groupTypes[] = UserGroup::GUESTS;
+                       }
+                       
+                       $this->userGroups = UserGroup::getGroupsByType($groupTypes);
                        foreach ($this->userGroups as $key => $userGroup) {
                                if (!$userGroup->isAccessible()) {
                                        unset($this->userGroups[$key]);
@@ -218,4 +224,11 @@ HTML;
                        throw new UserInputException('notGroupIDs', 'groupIDsIntersection');
                }
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index 0b343582532b0c34c03c7f137700fff1118284cc..09070c577983719d42c9facfc7586f6d835c9fee 100644 (file)
@@ -17,7 +17,7 @@ use wcf\system\WCF;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserIntegerPropertyCondition extends AbstractIntegerCondition implements IUserCondition {
+class UserIntegerPropertyCondition extends AbstractIntegerCondition implements INoticeCondition, IUserCondition {
        /**
         * @see \wcf\system\condition\AbstractIntegerCondition::$maxValueErrorMessage
         */
@@ -76,4 +76,13 @@ class UserIntegerPropertyCondition extends AbstractIntegerCondition implements I
        protected function getLabel($identifier) {
                return WCF::getLanguage()->get('wcf.user.condition.'.$this->getDecoratedObject()->propertyname.'.'.$identifier);
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               if (!WCF::getUser()->userID) return;
+               
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index ba9e0f571cb1cb11f3ed944fe7e91c2346778f47..eeeb8c589f0822ca1871fc30e375081638b08bf6 100644 (file)
@@ -18,7 +18,7 @@ use wcf\util\ArrayUtil;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserLanguageCondition extends AbstractSingleFieldCondition implements IUserCondition {
+class UserLanguageCondition extends AbstractSingleFieldCondition implements INoticeCondition, IUserCondition {
        /**
         * @see \wcf\system\condition\AbstractSingleFieldCondition::$label
         */
@@ -41,7 +41,7 @@ class UserLanguageCondition extends AbstractSingleFieldCondition implements IUse
         * @see \wcf\system\condition\IUserCondition::checkUser()
         */
        public function checkUser(Condition $condition, User $user) {
-               if (!empty($condition->languageIDs) && !in_array($user->languageID, $condition->languageIDs)) {
+               if (!empty($condition->conditionData['languageIDs']) && !in_array($user->languageID, $condition->languageIDs)) {
                        return false;
                }
                
@@ -108,4 +108,11 @@ class UserLanguageCondition extends AbstractSingleFieldCondition implements IUse
                        }
                }
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index 812f1e584ddfe16cbc1c394696a802c14ebe3404..1d637cdcd071dc15ffb00e090e7e5d4cf65dfa13 100644 (file)
@@ -17,7 +17,7 @@ use wcf\system\WCF;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserOptionsCondition extends AbstractMultipleFieldsCondition implements IUserCondition {
+class UserOptionsCondition extends AbstractMultipleFieldsCondition implements INoticeCondition, IUserCondition {
        /**
         * user option handler object
         * @var \wcf\system\option\user\UserOptionHandler
@@ -127,4 +127,13 @@ class UserOptionsCondition extends AbstractMultipleFieldsCondition implements IU
        public function setData(Condition $condition) {
                $this->optionHandler->setOptionValues($condition->conditionData['optionValues']);
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               if (!WCF::getUser()->userID) return;
+               
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index b0a95eeee7edd49ade0d2debceb77b9020f676a7..97070225b711d2ff44e4af87738831b039dfb801 100644 (file)
@@ -16,7 +16,7 @@ use wcf\system\WCF;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserRegistrationDateCondition extends AbstractSingleFieldCondition implements IUserCondition {
+class UserRegistrationDateCondition extends AbstractSingleFieldCondition implements INoticeCondition, IUserCondition {
        /**
         * @see \wcf\system\condition\AbstractSingleFieldCondition::$label
         */
@@ -149,4 +149,13 @@ HTML;
                        throw new UserInputException($this->fieldName, 'endBeforeStart');
                }
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               if (!WCF::getUser()->userID) return;
+               
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index 4b989eae27e2240e64d7c12ea1e64485b7865d73..0d41d86d5082640dae6ff468c39e72fd1c643227 100644 (file)
@@ -18,7 +18,7 @@ use wcf\system\WCF;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserRegistrationDateIntervalCondition extends AbstractIntegerCondition implements IUserCondition {
+class UserRegistrationDateIntervalCondition extends AbstractIntegerCondition implements INoticeCondition, IUserCondition {
        /**
         * @see \wcf\system\condition\AbstractMultipleFieldsCondition::$languageItemPrefix
         */
@@ -86,4 +86,13 @@ class UserRegistrationDateIntervalCondition extends AbstractIntegerCondition imp
        protected function getLabel($identifier) {
                return WCF::getLanguage()->get('wcf.user.condition.registrationDateInterval.'.$identifier);
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               if (!WCF::getUser()->userID) return;
+               
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index 919a444468cb5a375f3439a4f7cd0ccf81988ded..e2cfffab691db1dd78a80f4b3f3719375fd30808 100644 (file)
@@ -16,7 +16,7 @@ use wcf\system\WCF;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserStateCondition extends AbstractSingleFieldCondition implements IUserCondition {
+class UserStateCondition extends AbstractSingleFieldCondition implements INoticeCondition, IUserCondition {
        /**
         * @see \wcf\system\condition\AbstractSingleFieldCondition::$label
         */
@@ -191,4 +191,13 @@ HTML;
                        throw new UserInputException('userisEnabled', 'conflict');
                }
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               if (!WCF::getUser()->userID) return;
+               
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
index 61ea094fb60685f8125ed1a195ed03b918660cf5..7b7ccd1d5de6329509fefe210bbafc14d4171b6c 100644 (file)
@@ -16,7 +16,7 @@ use wcf\util\StringUtil;
  * @subpackage system.condition
  * @category   Community Framework
  */
-class UserUsernameCondition extends AbstractTextCondition implements IUserCondition {
+class UserUsernameCondition extends AbstractTextCondition implements INoticeCondition, IUserCondition {
        /**
         * @see \wcf\system\condition\AbstractTextCondition::$fieldName
         */
@@ -40,4 +40,13 @@ class UserUsernameCondition extends AbstractTextCondition implements IUserCondit
        public function checkUser(Condition $condition, User $user) {
                return mb_strpos($user->username, $condition->username) !== false;
        }
+       
+       /**
+        * @see \wcf\system\condition\INoticeCondition::showNotice()
+        */
+       public function showNotice(Condition $condition) {
+               if (!WCF::getUser()->userID) return;
+               
+               return $this->checkUser($condition, WCF::getUser());
+       }
 }
diff --git a/wcfsetup/install/files/lib/system/notice/NoticeHandler.class.php b/wcfsetup/install/files/lib/system/notice/NoticeHandler.class.php
new file mode 100644 (file)
index 0000000..b9583ee
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+namespace wcf\system\notice;
+use wcf\system\cache\builder\NoticeCacheBuilder;
+use wcf\system\SingletonFactory;
+
+/**
+ * Handles notice-related matters.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2014 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.notice
+ * @category   Community Framework
+ */
+class NoticeHandler extends SingletonFactory {
+       /**
+        * list with all enabled notices
+        * @var array<\wcf\data\notice\Notice>
+        */
+       protected $notices = array();
+       
+       /**
+        * @see \wcf\system\SingletonFacetory::init()
+        */
+       protected function init() {
+               $this->notices = NoticeCacheBuilder::getInstance()->getData();
+       }
+       
+       /**
+        * Returns the notices which are visible for the active user.
+        * 
+        * @return      array<\wcf\data\notice\Notice>
+        */
+       public function getVisibleNotices() {
+               $notices = array();
+               foreach ($this->notices as $notice) {
+                       $checkFailed = false;
+                       $conditions = $notice->getConditions();
+                       foreach ($conditions as $condition) {
+                               if (!$condition->getObjectType()->getProcessor()->showNotice($condition)) {
+                                       $checkFailed = true;
+                                       break;
+                               }
+                       }
+                       
+                       if (!$checkFailed && !$notice->isDismissed()) {
+                               $notices[$notice->noticeID] = $notice;
+                       }
+               }
+               
+               return $notices;
+       }
+}
index 6672c72d4d3e0518caaeba3307ae379e3bba17ad..86cab947d530906871c32660724e866e8b8fdb18 100644 (file)
                <item name="wcf.acp.group.assignment.list"><![CDATA[Automatische Benutzergruppen-Zuordnungen]]></item>
                <item name="wcf.acp.group.assignment.userGroup"><![CDATA[Benutzergruppe]]></item>
                <item name="wcf.acp.group.assignment.isDisabled"><![CDATA[Automatische Zuordnung deaktivieren]]></item>
+               <item name="wcf.acp.group.option.category.admin.content.notice"><![CDATA[Hinweise]]></item>
+               <item name="wcf.acp.group.option.admin.content.notice.canManageNotice"><![CDATA[Kann Hinweise verwalten]]></item>
                <item name="wcf.acp.group.option.user.profile.aboutMeMaxLength"><![CDATA[Maximallänge „Über mich“]]></item>
                <item name="wcf.acp.group.option.user.profile.canReportContent"><![CDATA[Kann Inhalte melden]]></item>
        </category>
                <item name="wcf.acp.menu.link.maintenance.rebuildData"><![CDATA[Anzeigen aktualisieren]]></item>
                <item name="wcf.acp.menu.link.log.stat"><![CDATA[Statistiken]]></item>
                <item name="wcf.acp.menu.link.group.assignment"><![CDATA[Automatische Zuordnungen]]></item>
+               <item name="wcf.acp.menu.link.notice"><![CDATA[Hinweise]]></item>
+               <item name="wcf.acp.menu.link.notice.add"><![CDATA[Hinweis hinzufügen]]></item>
+               <item name="wcf.acp.menu.link.notice.list"><![CDATA[Hinweise auflisten]]></item>
+       </category>
+       
+       <category name="wcf.acp.notice">
+               <item name="wcf.acp.notice.add"><![CDATA[Hinweis hinzufügen]]></item>
+               <item name="wcf.acp.notice.conditions"><![CDATA[Bedingungen]]></item>
+               <item name="wcf.acp.notice.conditions.description"><![CDATA[Werden keine Bedingungen ausgewählt, wird der Hinweis für jeden Benutzer auf allen Seiten angezeigt.]]></item>
+               <item name="wcf.acp.notice.conditions.page"><![CDATA[Seite]]></item>
+               <item name="wcf.acp.notice.conditions.page.description"><![CDATA[Die vom Benutzer aufgerufene Seite muss folgende Bedingungen erfüllen, damit der Hinweis angezeigt wird.]]></item>
+               <item name="wcf.acp.notice.conditions.user"><![CDATA[Aktiver Benutzer]]></item>
+               <item name="wcf.acp.notice.conditions.user.description"><![CDATA[Der aktive Benutzer muss die folgenden Bedingungen erfüllen, damit der Hinweis angezeigt wird.]]></item>
+               <item name="wcf.acp.notice.delete.confirmMessage"><![CDATA[Wollen Sie diesen Hinweis wirklich löschen?]]></item>
+               <item name="wcf.acp.notice.edit"><![CDATA[Hinweis bearbeiten]]></item>
+               <item name="wcf.acp.notice.isDisabled"><![CDATA[Hinweis deaktivieren]]></item>
+               <item name="wcf.acp.notice.isDismissible"><![CDATA[Benutzer kann Hinweis ausblenden]]></item>
+               <item name="wcf.acp.notice.isDismissible.description"><![CDATA[Ein einmal von einem Benutzer ausgeblender Hinweis wird bei erneutem Seitenaufruf nicht mehr angezeigt.]]></item>
+               <item name="wcf.acp.notice.list"><![CDATA[Hinweise]]></item>
+               <item name="wcf.acp.notice.notice"><![CDATA[Hinweis]]></item>
+               <item name="wcf.acp.notice.noticeUseHtml"><![CDATA[HTML im Hinweis verwenden]]></item>
+               <item name="wcf.acp.notice.resetIsDismissed"><![CDATA[Ausgeblendete Hinweise erneut anzeigen]]></item>
+               <item name="wcf.acp.notice.resetIsDismissed.description"><![CDATA[Der Hinweis wird jenen Benutzern wieder angezeigt, die die ursprüngliche Version bereits ausgeblendet haben. Gästen, die den Hinweis bereits ausgeblendet haben, wird dieser nur in einer neuen Session erneut angezeigt.]]></item>
+               <item name="wcf.acp.notice.showOrder"><![CDATA[Position]]></item>
+               <item name="wcf.acp.notice.showOrder.description"><![CDATA[Legt die Reihenfolge fest, in der die Hinweise angezeigt werden.]]></item>
        </category>
        
        <category name="wcf.acp.option">
@@ -2023,6 +2050,10 @@ Fehler sind beispielsweise:
                <item name="wcf.moderation.report.success"><![CDATA[Der Inhalt wurde den Moderatoren gemeldet.]]></item>
        </category>
        
+       <category name="wcf.notice">
+               <item name="wcf.notice.button.dismiss"><![CDATA[Hinweis dauerhaft ausblenden]]></item>
+       </category>
+       
        <category name="wcf.page">
                <item name="wcf.page.pageNo"><![CDATA[Seite {#$pageNo}]]></item>
                <item name="wcf.page.offline"><![CDATA[Die Seite befindet sich zurzeit {if OFFLINE_MESSAGE != ''}aus folgenden Gründen im Wartungsmodus:{else}im Wartungsmodus.{/if}]]></item>
@@ -2031,6 +2062,7 @@ Fehler sind beispielsweise:
                <item name="wcf.page.pagePosition"><![CDATA[Seite {#$pageNo} von {#$pages}]]></item>
                <item name="wcf.page.sitemap.userAccount"><![CDATA[Benutzerkonto]]></item>
                <item name="wcf.page.javascriptDisabled"><![CDATA[In Ihrem Webbrowser ist JavaScript deaktiviert. Um alle Funktionen dieser Webseite nutzen zu können, muss JavaScript aktiviert sein.]]></item>
+               <item name="wcf.page.requestedPage"><![CDATA[Aufgerufene Seite]]></item>
                <item name="wcf.page.privacyPolicy"><![CDATA[Datenschutzerklärung]]></item>
                <item name="wcf.page.privacyPolicy.text"><![CDATA[<h2>Datenschutz</h2>
     <p>Die Nutzung unserer Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, 
index 0745050ef6802dfb4bbcb8ad0034e0f0711b9df7..b3c3d926470a7ba1ad9224505ebfcd5a50721cbd 100644 (file)
@@ -491,6 +491,24 @@ CREATE TABLE wcf1_modification_log (
        additionalData MEDIUMTEXT
 );
 
+DROP TABLE IF EXISTS wcf1_notice;
+CREATE TABLE wcf1_notice (
+       noticeID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+       noticeName VARCHAR(255) NOT NULL,
+       notice MEDIUMTEXT,
+       noticeUseHtml TINYINT(1) NOT NULL DEFAULT 0,
+       showOrder INT(10) NOT NULL DEFAULT 0,
+       isDisabled TINYINT(1) NOT NULL DEFAULT 0,
+       isDismissible TINYINT(1) NOT NULL DEFAULT 0
+);
+
+DROP TABLE IF EXISTS wcf1_notice_dismissed;
+CREATE TABLE wcf1_notice_dismissed (
+       noticeID INT(10) NOT NULL,
+       userID INT(10) NOT NULL,
+       PRIMARY KEY (noticeID, userID)
+);
+
 DROP TABLE IF EXISTS wcf1_object_type;
 CREATE TABLE wcf1_object_type (
        objectTypeID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
@@ -1590,6 +1608,9 @@ ALTER TABLE wcf1_poll_option_vote ADD FOREIGN KEY (pollID) REFERENCES wcf1_poll
 ALTER TABLE wcf1_poll_option_vote ADD FOREIGN KEY (optionID) REFERENCES wcf1_poll_option (optionID) ON DELETE CASCADE;
 ALTER TABLE wcf1_poll_option_vote ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
 
+ALTER TABLE wcf1_notice_dismissed ADD FOREIGN KEY (noticeID) REFERENCES wcf1_notice (noticeID) ON DELETE CASCADE;
+ALTER TABLE wcf1_notice_dismissed ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
+
 /* SQL_PARSER_OFFSET */
 
 /* default inserts */