Preserving notifications instead of discarding them
authorAlexander Ebert <ebert@woltlab.com>
Wed, 28 May 2014 22:21:08 +0000 (00:21 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 28 May 2014 22:21:08 +0000 (00:21 +0200)
com.woltlab.wcf/templates/notificationList.tpl
wcfsetup/install/files/js/WCF.User.js
wcfsetup/install/files/lib/data/user/notification/UserNotificationAction.class.php
wcfsetup/install/files/lib/system/user/notification/UserNotificationHandler.class.php
wcfsetup/install/files/style/layout.less
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index ba147cfd1362fafb5ccf4240e4f3daf4afed5408..d1ecb74e59dccbce9b95782035b0a5f05f88ce8d 100644 (file)
@@ -24,7 +24,7 @@
 {include file='header' sidebarOrientation='left'}
 
 <header class="boxHeadline">
-       <h1>{lang}wcf.user.notification.notifications{/lang} <span class="badge jsNotificationsBadge">{#$__wcf->getUserNotificationHandler()->getNotificationCount()}</span></h1>
+       <h1>{lang}wcf.user.notification.notifications{/lang} <span class="badge jsNotificationsBadge">{#$__wcf->getUserNotificationHandler()->countAllNotifications()}</span></h1>
 </header>
 
 {include file='userNotice'}
@@ -36,7 +36,7 @@
                <nav>
                        <ul>
                                {content}
-                                       {if $notifications[notifications]}<li class="jsOnly"><a class="button jsMarkAllAsConfirmed"><span class="icon icon16 icon-remove"></span> <span>{lang}wcf.user.notification.markAllAsConfirmed{/lang}</span></a></li>{/if}
+                                       {if $__wcf->getUserNotificationHandler()->getNotificationCount()}<li class="jsOnly"><a class="button jsMarkAllAsConfirmed"><span class="icon icon16 fa-check"></span> <span>{lang}wcf.user.notification.markAllAsConfirmed{/lang}</span></a></li>{/if}
                                        
                                        {event name='contentNavigationButtonsTop'}
                                {/content}
@@ -60,6 +60,8 @@
                                                <div class="details">
                                                        <div class="containerHeadline">
                                                                <h3>
+                                                                       {if !$notification[confirmed]}<span class="badge label newContentBadge">{lang}wcf.message.new{/lang}</span>{/if}
+                                                                       
                                                                        {if $notification[event]->getAuthor()->userID}
                                                                                <a href="{link controller='User' object=$notification[event]->getAuthor()}{/link}" class="userLink" data-user-id="{@$notification[event]->getAuthor()->userID}">{$notification[event]->getAuthor()->username}</a>
                                                                        {else}
                                                        
                                                        <p>{@$notification[event]->getMessage()}</p>
                                                        
-                                                       <nav class="jsMobileNavigation buttonGroupNavigation">
-                                                               <ul class="buttonList iconList jsOnly">
-                                                                       <li><a class="jsMarkAsConfirmed jsTooltip" title="{lang}wcf.user.notification.markAsConfirmed{/lang}"><span class="icon icon16 icon-remove"></span></a></li>
-                                                               </ul>
-                                                       </nav>
+                                                       {if !$notification[confirmed]}
+                                                               <nav class="jsMobileNavigation buttonGroupNavigation">
+                                                                       <ul class="buttonList iconList jsOnly">
+                                                                               <li><a class="jsMarkAsConfirmed jsTooltip" title="{lang}wcf.user.notification.markAsConfirmed{/lang}"><span class="icon icon16 fa-check"></span></a></li>
+                                                                       </ul>
+                                                               </nav>
+                                                       {/if}
                                                </div>
                                        </div>
                                </li>
index 48cc48e1492eb62700a592fe6b7549893b18c734..8e346c67c59ec4a11ae98acc7485e8d5c7e100b2 100644 (file)
@@ -1264,10 +1264,8 @@ WCF.Notification.UserPanel = WCF.UserPanel.extend({
         */
        _addDefaultItems: function(dropdownMenu) {
                this._addDivider(dropdownMenu);
-               if (this._container.data('count')) {
-                       $('<li><a href="' + this._showAllLink + '">' + WCF.Language.get('wcf.user.notification.showAll') + '</a></li>').appendTo(dropdownMenu);
-                       this._addDivider(dropdownMenu);
-               }
+               $('<li><a href="' + this._showAllLink + '">' + WCF.Language.get('wcf.user.notification.showAll') + '</a></li>').appendTo(dropdownMenu);
+               this._addDivider(dropdownMenu);
                $('<li id="userNotificationsMarkAllAsConfirmed"><a>' + WCF.Language.get('wcf.user.notification.markAllAsConfirmed') + '</a></li>').click($.proxy(this._markAllAsConfirmed, this)).appendTo(dropdownMenu);
        },
        
@@ -1462,11 +1460,8 @@ WCF.Notification.List = Class.extend({
                                        return;
                                }
                                
-                               this._items[data.returnValues.notificationID].remove();
-                               delete this._items[data.returnValues.notificationID];
-                               
-                               // reduce badge count
-                               this._badge.html(data.returnValues.totalCount);
+                               this._items[data.returnValues.notificationID].find('.newContentBadge').remove();
+                               this._items[data.returnValues.notificationID].find('.jsMarkAsConfirmed').parents('nav:eq(0)').remove();
                                
                                // remove previous notification count
                                document.title = document.title.replace(/^\(([0-9]+)\) /, '');
@@ -1475,6 +1470,15 @@ WCF.Notification.List = Class.extend({
                                if (data.returnValues.totalCount > 0) {
                                        document.title = '(' + data.returnValues.totalCount + ') ' + document.title;
                                }
+                               else {
+                                       var $listItem = $('.contentNavigation .jsMarkAllAsConfirmed').parent();
+                                       var $list = $listItem.parent();
+                                       $listItem.remove();
+                                       
+                                       if (!$list.children('li').length) {
+                                               $list.parents('nav:eq(0)').remove();
+                                       }
+                               }
                        break;
                }
        }
index d4257d91c329bcf08498a77a18a05ca96b90ed33..9288bb13b4fee49340a30d572d8c8bc216126695 100644 (file)
@@ -110,26 +110,17 @@ class UserNotificationAction extends AbstractDatabaseObjectAction {
         */
        public function markAsConfirmed() {
                if (!isset($this->parameters['alreadyConfirmed'])) {
-                       $sql = "DELETE FROM     wcf".WCF_N."_user_notification_to_user
-                               WHERE           notificationID = ?
-                                               AND userID = ?";
+                       $sql = "UPDATE  wcf".WCF_N."_user_notification_to_user
+                               SET     confirmed = ?
+                               WHERE   notificationID = ?
+                                       AND userID = ?";
                        $statement = WCF::getDB()->prepareStatement($sql);
                        $statement->execute(array(
+                               1,
                                $this->parameters['notificationID'],
                                WCF::getUser()->userID
                        ));
                        
-                       // remove entirely read notifications
-                       $sql = "SELECT  COUNT(*) as count
-                               FROM    wcf".WCF_N."_user_notification_to_user
-                               WHERE   notificationID = ?";
-                       $statement = WCF::getDB()->prepareStatement($sql);
-                       $statement->execute(array($this->parameters['notificationID']));
-                       $row = $statement->fetchArray();
-                       if (!$row['count']) {
-                               UserNotificationEditor::deleteAll(array($this->parameters['notificationID']));
-                       }
-                       
                        // reset notification count
                        UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'userNotificationCount');
                }
@@ -150,10 +141,14 @@ class UserNotificationAction extends AbstractDatabaseObjectAction {
         */
        public function markAllAsConfirmed() {
                // remove notifications for this user
-               $sql = "DELETE FROM     wcf".WCF_N."_user_notification_to_user
-                       WHERE           userID = ?";
+               $sql = "UPDATE  wcf".WCF_N."_user_notification_to_user
+                       SET     confirmed = ?
+                       WHERE   userID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array(WCF::getUser()->userID));
+               $statement->execute(array(
+                       1,
+                       WCF::getUser()->userID
+               ));
                
                // reset notification count
                UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'userNotificationCount');
index dbd16880fc6717e5702aa6a9ffc1d2be48ad4d2c..867db78d8e6622791d00f13e01ccf74288e8a3a6 100644 (file)
@@ -191,6 +191,7 @@ class UserNotificationHandler extends SingletonFactory {
                                        $conditionBuilder = new PreparedStatementConditionBuilder();
                                        $conditionBuilder->add('notification.notificationID = notification_to_user.notificationID');
                                        $conditionBuilder->add('notification_to_user.userID = ?', array(WCF::getUser()->userID));
+                                       $conditionBuilder->add('notification_to_user.confirmed = ?', array(0));
                                        
                                        $sql = "SELECT  COUNT(*) AS count
                                                FROM    wcf".WCF_N."_user_notification_to_user notification_to_user,
@@ -213,23 +214,41 @@ class UserNotificationHandler extends SingletonFactory {
                return $this->notificationCount;
        }
        
+       /**
+        * Counts all existing notifications for current user and returns it.
+        * 
+        * @return      integer
+        */
+       public function countAllNotifications() {
+               $sql = "SELECT  COUNT(*) AS count
+                       FROM    wcf".WCF_N."_user_notification_to_user
+                       WHERE   userID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array(WCF::getUser()->userID));
+               $row = $statement->fetchArray();
+               
+               return $row['count'];
+       }
+       
        /**
         * Returns a limited list of outstanding notifications.
         * 
         * @param       integer         $limit
         * @param       integer         $offset
+        * @param       boolean         $showConfirmedNotifications
         * @return      array<array>
         */
-       public function getNotifications($limit = 5, $offset = 0) {
+       public function getNotifications($limit = 5, $offset = 0, $showConfirmedNotifications = false) {
                // build enormous query
                $conditions = new PreparedStatementConditionBuilder();
                $conditions->add("notification_to_user.userID = ?", array(WCF::getUser()->userID));
+               if (!$showConfirmedNotifications) $conditions->add("notification_to_user.confirmed = ?", array(0));
                $conditions->add("notification.notificationID = notification_to_user.notificationID");
                
                $sql = "SELECT          notification_to_user.notificationID, notification_event.eventID,
                                        object_type.objectType, notification.objectID,
                                        notification.additionalData, notification.authorID,
-                                       notification.time
+                                       notification.time".($showConfirmedNotifications ? ", notification_to_user.confirmed" : "")."
                        FROM            wcf".WCF_N."_user_notification_to_user notification_to_user,
                                        wcf".WCF_N."_user_notification notification
                        LEFT JOIN       wcf".WCF_N."_user_notification_event notification_event
@@ -308,6 +327,10 @@ class UserNotificationHandler extends SingletonFactory {
                                'time' => $event['time']
                        );
                        
+                       if ($showConfirmedNotifications) {
+                               $data['confirmed'] = $event['confirmed'];
+                       }
+                       
                        $notifications[] = $data;
                }
                
@@ -459,14 +482,31 @@ class UserNotificationHandler extends SingletonFactory {
        }
        
        /**
-        * Deletes notifications.
+        * This method does not delete notifications, instead it marks them as confirmed. The system
+        * does not allow to delete them, but since it was intended in WCF 2.0, this method only
+        * exists for compatibility reasons.
         * 
+        * Please consider replacing your calls with markAsConfirmed().
+        * 
+        * @deprecated
         * @param       string          $eventName
         * @param       string          $objectType
         * @param       array<integer>  $recipientIDs
         * @param       array<integer>  $objectIDs
         */
        public function deleteNotifications($eventName, $objectType, array $recipientIDs, array $objectIDs = array()) {
+               $this->markAsConfirmed($eventName, $objectType, $recipientIDs, $objectIDs);
+       }
+       
+       /**
+        * Marks notifications as confirmed
+        * 
+        * @param       string          $eventName
+        * @param       string          $objectType
+        * @param       array<integer>  $recipientIDs
+        * @param       array<integer>  $objectIDs
+        */
+       public function markAsConfirmed($eventName, $objectType, array $recipientIDs, array $objectIDs = array()) {
                // check given object type and event name
                if (!isset($this->availableEvents[$objectType][$eventName])) {
                        throw new SystemException("Unknown event ".$objectType."-".$eventName." given");
@@ -477,16 +517,17 @@ class UserNotificationHandler extends SingletonFactory {
                $event = $this->availableEvents[$objectType][$eventName];
                
                // delete notifications
-               $sql = "DELETE FROM     wcf".WCF_N."_user_notification_to_user
-                       WHERE           notificationID IN (
-                                               SELECT  notificationID
-                                               FROM    wcf".WCF_N."_user_notification
-                                               WHERE   packageID = ?
-                                                       AND eventID = ?
-                                                       ".(!empty($objectIDs) ? "AND objectID IN (?".(count($objectIDs) > 1 ? str_repeat(',?', count($objectIDs) - 1) : '').")" : '')." 
-                                       )
-                                       ".(!empty($recipientIDs) ? ("AND userID IN (?".(count($recipientIDs) > 1 ? str_repeat(',?', count($recipientIDs) - 1) : '').")") : '');
-               $parameters = array($objectTypeObject->packageID, $event->eventID);
+               $sql = "UPDATE  wcf".WCF_N."_user_notification_to_user
+                       SET     confirmed = ?
+                       WHERE   notificationID IN (
+                                       SELECT  notificationID
+                                       FROM    wcf".WCF_N."_user_notification
+                                       WHERE   packageID = ?
+                                               AND eventID = ?
+                                               ".(!empty($objectIDs) ? "AND objectID IN (?".(count($objectIDs) > 1 ? str_repeat(',?', count($objectIDs) - 1) : '').")" : '')." 
+                               )
+                               ".(!empty($recipientIDs) ? ("AND userID IN (?".(count($recipientIDs) > 1 ? str_repeat(',?', count($recipientIDs) - 1) : '').")") : '');
+               $parameters = array(1, $objectTypeObject->packageID, $event->eventID);
                if (!empty($objectIDs)) $parameters = array_merge($parameters, $objectIDs);
                if (!empty($recipientIDs)) $parameters = array_merge($parameters, $recipientIDs);
                $statement = WCF::getDB()->prepareStatement($sql);
index 55093e30996ccd7aea7c958a76097613d54ec143..a7e320e074eabaa8fee1c230604f6cf04d236610 100644 (file)
@@ -994,13 +994,24 @@ html[dir="rtl"] {
                                }
                        }
                        
-                       > .containerHeadline > .containerContentType {
-                               color: lighten(@wcfDimmedColor, 20%);
-                               position: absolute;
-                               right: 0;
-                               top: 3px;
+                       > .containerHeadline {
+                               > .containerContentType {
+                                       color: lighten(@wcfDimmedColor, 20%);
+                                       position: absolute;
+                                       right: 0;
+                                       top: 3px;
+                                       
+                                       .transition(color, .1s);
+                               }
                                
-                               .transition(color, .1s);
+                               .newContentBadge {
+                                       //background-color: darken(@wcfTabularBoxBackgroundColor, 10%);
+                                       color: @wcfTabularBoxColor;
+                                       text-transform: uppercase;
+                                       
+                                       .textShadow(darken(@wcfTabularBoxBackgroundColor, 10%));
+                                       .linearGradient(darken(@wcfTabularBoxBackgroundColor, 10%), @wcfTabularBoxBackgroundColor, darken(@wcfTabularBoxBackgroundColor, 10%));
+                               }
                        }
                }
        }
index ac829df136ef33b79494324925df54f68c9e2268..78007a7cbe727d00ff4d9ee1b8371c032a24692f 100644 (file)
@@ -2718,10 +2718,10 @@ Möchten Sie diese E-Mail-Benachrichtigung in Zukunft nicht mehr erhalten, könn
                <item name="wcf.user.notification.mailNotificationType.instant"><![CDATA[Sofortige E-Mail-Benachrichtigung]]></item>
                <item name="wcf.user.notification.mailNotificationType.daily"><![CDATA[Tägliche E-Mail-Benachrichtigung]]></item>
                <item name="wcf.user.notification.markAllAsConfirmed"><![CDATA[Alle Benachrichtigungen verwerfen]]></item>
-               <item name="wcf.user.notification.markAllAsConfirmed.confirmMessage"><![CDATA[Wollen Sie wirklich alle Benachrichtigungen verwerfen?]]></item>
-               <item name="wcf.user.notification.markAsConfirmed"><![CDATA[Verwerfen]]></item>
-               <item name="wcf.user.notification.noMoreNotifications"><![CDATA[Keine weiteren Benachrichtigungen]]></item>
-               <item name="wcf.user.notification.noNotifications"><![CDATA[Es sind keine neuen Benachrichtigungen vorhanden.]]></item>
+               <item name="wcf.user.notification.markAllAsConfirmed.confirmMessage"><![CDATA[Wollen Sie wirklich alle Benachrichtigungen als gelesen markieren?]]></item>
+               <item name="wcf.user.notification.markAsConfirmed"><![CDATA[Alls gelesen markieren]]></item>
+               <item name="wcf.user.notification.noMoreNotifications"><![CDATA[Keine neuen Benachrichtigungen]]></item>
+               <item name="wcf.user.notification.noNotifications"><![CDATA[Sie haben keine Benachrichtigungen.]]></item>
                <item name="wcf.user.notification.notifications"><![CDATA[Benachrichtigungen]]></item>
                <item name="wcf.user.notification.showAll"><![CDATA[Alle Benachrichtigungen anzeigen]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.user"><![CDATA[Benutzer-Profile]]></item>
index 3652b21b7ee78dee8b72d8859c74480664768568..06f78bf8a0f60c7c6f58465905826e98531ee0a1 100644 (file)
@@ -2569,11 +2569,11 @@ If you do not want to receive further email notifications for this event, you ca
                <item name="wcf.user.notification.mailNotificationType.none"><![CDATA[No Email Notification]]></item>
                <item name="wcf.user.notification.mailNotificationType.instant"><![CDATA[Instant Email Notification]]></item>
                <item name="wcf.user.notification.mailNotificationType.daily"><![CDATA[Daily Email Notification]]></item>
-               <item name="wcf.user.notification.markAllAsConfirmed"><![CDATA[Discard All Notifications]]></item>
-               <item name="wcf.user.notification.markAllAsConfirmed.confirmMessage"><![CDATA[Do you really want to discard all notifications?]]></item>
-               <item name="wcf.user.notification.markAsConfirmed"><![CDATA[Discard]]></item>
-               <item name="wcf.user.notification.noMoreNotifications"><![CDATA[No more notifications]]></item>
-               <item name="wcf.user.notification.noNotifications"><![CDATA[There are no more notifications.]]></item>
+               <item name="wcf.user.notification.markAllAsConfirmed"><![CDATA[Mark All as Read]]></item>
+               <item name="wcf.user.notification.markAllAsConfirmed.confirmMessage"><![CDATA[Do you really want to mark all notifications as read?]]></item>
+               <item name="wcf.user.notification.markAsConfirmed"><![CDATA[Mark as Read]]></item>
+               <item name="wcf.user.notification.noMoreNotifications"><![CDATA[No new notifications]]></item>
+               <item name="wcf.user.notification.noNotifications"><![CDATA[You have no notifications.]]></item>
                <item name="wcf.user.notification.notifications"><![CDATA[Notifications]]></item>
                <item name="wcf.user.notification.showAll"><![CDATA[Show All Notifications]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.user"><![CDATA[User Profiles]]></item>
index a3c303891dd0cd9a45d3aea7a68e8a9c45a16f2f..4679694f8b2647211191d30bc0dbb4b9973108b0 100644 (file)
@@ -1208,6 +1208,7 @@ CREATE TABLE wcf1_user_notification_to_user (
        notificationID INT(10) NOT NULL,
        userID INT(10) NOT NULL,
        mailNotified TINYINT(1) NOT NULL DEFAULT 0,
+       confirmed TINYINT(1) NOT NULL DEFAULT 0,
        UNIQUE KEY notificationID (notificationID, userID)
 );