*.sln\r
*.phpproj\r
*.puo\r
-*.suo
\ No newline at end of file
+*.suo\r
+*.project
\ No newline at end of file
--- /dev/null
+{include file='header'}
+
+<div class="mainHeadline">
+ <img src="{@RELATIVE_WCF_DIR}icon/infoL.png" alt="" />
+ <div class="headlineContainer">
+ <h2>{lang}wcf.user.notification.settings{/lang}</h2>
+ </div>
+</div>
+
+{if $errorField}
+ <p class="error">{lang}wcf.global.form.error{/lang}</p>
+{/if}
+
+{if $success|isset && $success}
+ <p class="success">{lang}wcf.user.notification.settings.saved{/lang}</p>
+{/if}
+
+<form method="post" action="index.php?form=UserNotificationDefaultSettings">
+<div class="border tabMenuContent">
+ <div class="container-1">
+ <h3 class="subHeadline">{lang}wcf.user.notification.settings{/lang}</h3>
+
+ <div class="border borderMarginRemove">
+ <table class="tableList">
+ {foreach from=$notificationObjectTypes key=typeName item=data}
+ {assign var=objectType value=$data.object}
+ {assign var=events value=$data.events}
+ {cycle name="eventRows" values='container-1,container-2' print=false advance=false reset=true}
+ <thead>
+ <tr class="tableHead">
+ <th class="columnObjectType">
+ <div>
+ <h3 class="emptyHead">{lang}wcf.user.notification.object.type.{$typeName}{/lang}</h3>
+ </div>
+ </th>
+ {foreach from=$notificationTypes key=notificationTypeName item=notificationType}
+ <th class="columnNotificationType columnIcon">
+ <div>
+ <span class="emptyHead"><img src="{@RELATIVE_WCF_DIR}icon/{$notificationType->getIcon()}S.png" alt="{lang}wcf.user.notification.type.{$notificationTypeName}{/lang}" title="{lang}wcf.user.notification.type.{$notificationTypeName}{/lang}" /></span>
+ </div>
+ </th>
+ {/foreach}
+ </tr>
+ </thead>
+ <tbody>
+ {foreach from=$events key=eventName item=event}
+ <tr class="{cycle name="eventRows"}">
+ <td class="columnEvent columnText">
+ <p title="{$event->getDescription()}">{$event->getTitle()}</p>
+ <p class="smallFont">{$event->getDescription()}</p>
+ </td>
+ {foreach from=$event->supportedNotificationTypes key=supportedType item=supported}
+ <td class="columnNotificationType columnIcon">
+ <input value="1" type="checkbox" name="activeEventNotifications[{$typeName}][{$eventName}][{$supportedType}][enabled]"{if !$supported} disabled="disabled"{/if}{if $supported && $activeEventNotifications[$typeName][$eventName][$supportedType]['enabled']} checked="checked"{/if} />
+ <input value="1" type="checkbox" name="activeEventNotifications[{$typeName}][{$eventName}][{$supportedType}][canBeDisabled]"{if !$supported} disabled="disabled"{/if}{if $supported && $activeEventNotifications[$typeName][$eventName][$supportedType]['canBeDisabled']} checked="checked"{/if} />
+ </td>
+ {/foreach}
+ </tr>
+ {/foreach}
+ </tbody>
+ {/foreach}
+ </table>
+ </div>
+ </div>
+ </div>
+
+ <div class="formSubmit">
+ <input type="submit" accesskey="s" value="{lang}wcf.global.button.submit{/lang}" />
+ <input type="reset" accesskey="r" value="{lang}wcf.global.button.reset{/lang}" />
+ <input type="hidden" name="packageID" value="{@PACKAGE_ID}" />
+ {@SID_INPUT_TAG}
+ </div>
+</form>
+
+{include file='footer'}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/cronjobs.xsd">
+ <import>
+ <cronjob>
+ <classPath>lib/system/cronjob/CleanUpNotificationsCronjob.class.php</classPath>
+ <description>Cleans up notifications regularly</description>
+ <startMinute>*/30</startMinute>
+ <startHour>*</startHour>
+ <startDom>*</startDom>
+ <startMonth>*</startMonth>
+ <startDow>*</startDow>
+ <execMultiple>0</execMultiple>
+ <canbeedited>0</canbeedited>
+ <canbedisabled>0</canbedisabled>
+ <active>1</active>
+ </cronjob>
+ </import>
+</data>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/event-listener.xsd">
+ <import>
+ <eventlistener>
+ <eventClassName>StructuredTemplate</eventClassName>
+ <eventName>shouldDisplay</eventName>
+ <listenerClassFile>lib/system/event/listener/StructuredTemplateUserMessagesNotificationListener.class.php</listenerClassFile>
+ </eventlistener>
+ <eventlistener>
+ <eventClassName>StructuredTemplate</eventClassName>
+ <eventName>shouldDisplay</eventName>
+ <listenerClassFile>lib/system/event/listener/StructuredTemplateUserPanelNotificationListener.class.php</listenerClassFile>
+ </eventlistener>
+ </import>
+</data>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/acp/form/ACPForm.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationHandler.class.php');
+require_once(WCF_DIR.'lib/data/user/NotificationUser.class.php');
+
+/**
+ * Shows the notification settings form.
+ *
+ * @author Tim Düsterhus
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage form
+ * @category Community Framework
+ */
+class UserNotificationDefaultSettingsForm extends ACPForm {
+ /**
+ * @see AbstractPage::$templateName
+ */
+ public $templateName = 'userNotificationDefaultSettings';
+
+ /**
+ * An array holding all available notification object types
+ *
+ * @var array
+ */
+ public $notificationObjectTypes = array();
+
+ /**
+ * An array holding all available notification types
+ *
+ * @var array
+ */
+ public $notificationTypes = array();
+
+ /**
+ * The activated event notifications in the form
+ *
+ * @var array
+ */
+ public $activeEventNotifications = array();
+
+ /**
+ * The notification user object of the current user
+ *
+ * @var NotificationUser
+ */
+ public $notificationUser = null;
+
+ /**
+ * @see Page::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ $this->notificationUser = new NotificationUser(null, WCF::getUser());
+ $this->notificationObjectTypes = NotificationHandler::getAvailableNotificationObjectTypes();
+ $this->notificationTypes = NotificationHandler::getAvailableNotificationTypes();
+ }
+
+ /**
+ * @see Form::readFormParameters()
+ */
+ public function readFormParameters() {
+ parent::readFormParameters();
+
+ if (isset($_POST['activeEventNotifications']) && is_array($_POST['activeEventNotifications'])) $this->activeEventNotifications = $_POST['activeEventNotifications'];
+ }
+
+ /**
+ * @see Form::validate()
+ */
+ public function validate() {
+ parent::validate();
+
+ // validate checked options and unset wrong settings
+ foreach ($this->activeEventNotifications as $objectType => $events) {
+ if (!isset($this->notificationObjectTypes[$objectType])) {
+ unset ($this->activeEventNotifications[$objectType]);
+ continue;
+ }
+
+ foreach ($events as $eventName => $notificationTypes) {
+ if (!isset($this->notificationObjectTypes[$objectType]['events'][$eventName])) {
+ unset ($this->activeEventNotifications[$objectType][$eventName]);
+ continue;
+ }
+
+ foreach ($notificationTypes as $notificationType => $value) {
+ if (!isset($this->notificationTypes[$notificationType])) {
+ unset ($this->activeEventNotifications[$objectType][$eventName][$notificationType]);
+ continue;
+ }
+ }
+ }
+ }
+
+ $settings = array();
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_user_notification_event_settings
+ WHERE packageID IN (".NotificationHandler::getAvailablePackageIDs().")";
+ $result = WCF::getDB()->sendQuery($sql);
+ while($row = WCF::getDB()->fetchArray($result)) {
+ $settings[$row['objectType']][$row['eventName']][$row['notificationType']] = $row;
+ }
+
+ // add default values
+ foreach ($this->notificationObjectTypes as $name => $objectType) {
+ if (isset($objectType['events'])) {
+ foreach ($objectType['events'] as $eventName => $event) {
+ foreach ($this->notificationTypes as $typeName => $type) {
+ if (!isset($this->activeEventNotifications[$name][$eventName][$typeName]['canBeDisabled'])) {
+ $this->activeEventNotifications[$name][$eventName][$typeName]['canBeDisabled'] = 0;
+ }
+ if (!isset($this->activeEventNotifications[$name][$eventName][$typeName]['enabled'])) {
+ $this->activeEventNotifications[$name][$eventName][$typeName]['enabled'] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @see Page::readData()
+ */
+ public function readData() {
+ parent::readData();
+
+ $settings = array();
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_user_notification_event_settings
+ WHERE packageID IN (".NotificationHandler::getAvailablePackageIDs().")";
+ $result = WCF::getDB()->sendQuery($sql);
+ while($row = WCF::getDB()->fetchArray($result)) {
+ $settings[$row['objectType']][$row['eventName']][$row['notificationType']] = $row;
+ }
+
+ if (!count($_POST)) {
+ foreach ($this->notificationObjectTypes as $name => $objectType) {
+ if (isset($objectType['events'])) {
+ foreach ($objectType['events'] as $eventName => $event) {
+ foreach ($this->notificationTypes as $typeName => $type) {
+ if (isset($settings[$name][$eventName][$typeName]['canBeDisabled'])) {
+ $this->activeEventNotifications[$name][$eventName][$typeName]['canBeDisabled'] = $settings[$name][$eventName][$typeName]['canBeDisabled'];
+ }
+ else {
+ $this->activeEventNotifications[$name][$eventName][$typeName]['canBeDisabled'] = 1;
+ }
+ if (isset($settings[$name][$eventName][$typeName]['enabled'])) {
+ $this->activeEventNotifications[$name][$eventName][$typeName]['enabled'] = $settings[$name][$eventName][$typeName]['enabled'];
+ }
+ else {
+ $this->activeEventNotifications[$name][$eventName][$typeName]['enabled'] = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ($this->notificationTypes) {
+ // calculate compatibility map
+ foreach ($this->notificationObjectTypes as $name => $objectType) {
+ if (!isset($objectType['events']) || !is_array($objectType['events'])) {
+ unset ($this->notificationObjectTypes[$name]);
+ continue;
+ }
+ foreach ($objectType['events'] as $eventName => $event) {
+ $this->notificationObjectTypes[$name]['events'][$eventName]->supportedNotificationTypes = array();
+ foreach ($this->notificationTypes as $typeName => $type) {
+ $this->notificationObjectTypes[$name]['events'][$eventName]->supportedNotificationTypes[$typeName] = $event->supportsNotificationType($type);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @see Page::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'notificationObjectTypes' => $this->notificationObjectTypes,
+ 'notificationTypes' => $this->notificationTypes,
+ 'activeEventNotifications' => $this->activeEventNotifications,
+ 'user' => $this->notificationUser
+ ));
+ }
+
+ /**
+ * @see Page::show()
+ */
+ public function show() {
+ // check module
+ if (!MODULE_USER_NOTIFICATION) {
+ throw new IllegalLinkException();
+ }
+
+ // check permission
+ /*if (!WCF::getUser()->userID) {
+ throw new PermissionDeniedException();
+ }
+
+ // set active user cp menu item
+ UserCPMenu::getInstance()->setActiveMenuItem('wcf.user.usercp.menu.link.settings.notification');
+*/
+ // show form
+ parent::show();
+ }
+
+ /**
+ * @see Form::save()
+ */
+ public function save() {
+ parent::save();
+
+ // delete old data but only from this dependency tree
+ $sql = "DELETE FROM wcf".WCF_N."_user_notification_event_settings
+ WHERE packageID IN (".NotificationHandler::getAvailablePackageIDs().")";
+ WCF::getDB()->sendQuery($sql);
+
+ if ($this->notificationTypes) {
+ // calculate compatibility map
+ foreach ($this->notificationObjectTypes as $name => $objectType) {
+ if (!isset($objectType['events']) || !is_array($objectType['events'])) {
+ unset ($this->notificationObjectTypes[$name]);
+ continue;
+ }
+ foreach ($objectType['events'] as $eventName => $event) {
+ $this->notificationObjectTypes[$name]['events'][$eventName]->supportedNotificationTypes = array();
+ foreach ($this->notificationTypes as $typeName => $type) {
+ $this->notificationObjectTypes[$name]['events'][$eventName]->supportedNotificationTypes[$typeName] = $event->supportsNotificationType($type);
+ }
+ }
+ }
+ }
+
+ // prepare new data
+ $inserts = '';
+ foreach ($this->activeEventNotifications as $objectType => $events) {
+ foreach ($events as $eventName => $notificationTypes) {
+ foreach ($notificationTypes as $notificationType => $data) {
+ if ($data['enabled'] && $data['canBeDisabled']) continue;
+ if (!$this->notificationObjectTypes[$objectType]['events'][$eventName]->supportedNotificationTypes[$notificationType]) continue;
+ $objectTypeObject = NotificationHandler::getNotificationObjectTypeObject($objectType);
+ if (!empty($inserts)) $inserts .= ',';
+ $inserts .= "(".$objectTypeObject->getPackageID().",
+ '".escapeString($objectType)."',
+ '".escapeString($eventName)."',
+ '".escapeString($notificationType)."',
+ ".(!$data['enabled'] || $data['canBeDisabled'] ? "1" : "0").",
+ ".($data['enabled'] ? "1" : "0").")";
+ }
+ }
+
+ }
+
+ if (!empty($inserts)) {
+ $sql = "INSERT INTO wcf".WCF_N."_user_notification_event_settings
+ (packageID, objectType, eventName, notificationType, canBeDisabled, enabled)
+ VALUES
+ ".$inserts;
+ WCF::getDB()->sendQuery($sql);
+ }
+
+ $this->saved();
+
+ // show success message
+ WCF::getTPL()->assign('success', true);
+ }
+
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/action/AbstractSecureAction.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationEditor.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationList.class.php');
+require_once(WCF_DIR.'lib/data/user/NotificationUser.class.php');
+
+/**
+ * This action handles default confirmations of notifications
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage action
+ * @category Community Framework
+ */
+class NotificationConfirmAction extends AbstractSecureAction {
+ /**
+ * The id of the notification
+ *
+ * @var integer
+ */
+ public $notificationID = 0;
+
+ /**
+ * The notification editor object
+ *
+ * @var NotificationEditor
+ */
+ public $notification = null;
+
+ /**
+ * The url for redirection (non-ajax)
+ *
+ * @var string
+ */
+ public $url = null;
+
+ /**
+ * @see Action::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (!MODULE_USER_NOTIFICATION) {
+ throw new IllegalLinkException();
+ }
+
+ if (isset($_REQUEST['notificationID'])) {
+ $this->notificationID = intval($_REQUEST['notificationID']);
+
+ $this->notification = new NotificationEditor($this->notificationID);
+ // validate notification ID
+ if (!$this->notification->notificationID) {
+ throw new IllegalLinkException();
+ }
+ $this->notification->userID = explode(',', $this->notification->userID);
+ // validate user
+ if (!in_array(WCF::getUser()->userID, $this->notification->userID)) {
+ throw new PermissionDeniedException();
+ }
+ }
+
+ if (isset($_REQUEST['url'])) $this->url = rawurldecode(StringUtil::trim($_REQUEST['url']));
+ }
+
+ /**
+ * @see Action::execute()
+ */
+ public function execute() {
+ parent::execute();
+
+ // get user
+ $user = new NotificationUser(null, WCF::getUser(), false);
+
+ // mark single notification
+ if ($this->notificationID) {
+ if ($this->notification->confirmed) {
+ throw new NamedUserException(WCF::getLanguage()->get('wcf.user.notification.error.alreadyAccepted'));
+ }
+
+ $this->notification->markConfirmed();
+ }
+ // mark all outstanding notifications
+ else {
+ if ($user->hasOutstandingNotifications()) {
+ // get outstanding notifications
+ $notificationList = new NotificationList();
+ $notificationList->sqlConditions = "notification.userID = ".$user->userID;
+ $notificationList->readObjects();
+
+ $notifications = $notificationList->getObjects();
+ $notificationIDArray = array();
+
+ foreach ($notifications as $notification) {
+ if (!$notification->confirmed && !$notification->acceptURL) {
+ $notificationIDArray[] = $notification->notificationID;
+ }
+ }
+
+ NotificationEditor::markAllConfirmed($notificationIDArray, array(WCF::getUser()->userID));
+ }
+ }
+
+ // recalculate flags
+ $user->recalculateOutstandingNotifications();
+
+ $this->executed();
+ }
+
+ /**
+ * @see Action::executed()
+ */
+ public function executed() {
+ parent::executed();
+
+ if (!isset($_REQUEST['ajax'])) {
+ $this->checkURL();
+ HeaderUtil::redirect($this->url);
+ }
+ }
+
+ /**
+ * Gets the redirect url.
+ */
+ protected function checkURL() {
+ if (empty($this->url)) {
+ $this->url = 'index.php'.SID_ARG_1ST;
+ }
+ // append missing session id
+ else if (SID_ARG_1ST != '' && !preg_match('/(?:&|\?)s=[a-z0-9]{40}/', $this->url)) {
+ if (StringUtil::indexOf($this->url, '?') !== false) $this->url .= SID_ARG_2ND_NOT_ENCODED;
+ else $this->url .= SID_ARG_1ST;
+ }
+ }
+}
+?>
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/action/AbstractAction.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/Notification.class.php');
+require_once(WCF_DIR.'lib/data/user/UserEditor.class.php');
+
+/**
+ * This action disables notifications
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage action
+ * @category Community Framework
+ */
+class NotificationDisableAction extends AbstractAction {
+ /**
+ * The id of the notification
+ *
+ * @var integer
+ */
+ public $notificationID = 0;
+
+ /**
+ * The notification object
+ *
+ * @var Notification
+ */
+ public $notification = null;
+
+ /**
+ * The user editor object
+ *
+ * @var UserEditor
+ */
+ public $user = null;
+
+ /**
+ * The mail token
+ *
+ * @var string
+ */
+ public $token = '';
+
+ /**
+ * @see Action::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (!MODULE_USER_NOTIFICATION) {
+ throw new IllegalLinkException();
+ }
+
+ if (isset($_REQUEST['notificationID'])) {
+ $this->notificationID = intval($_REQUEST['notificationID']);
+
+ $this->notification = new Notification($this->notificationID);
+ // validate notification ID
+ if (!$this->notification->notificationID) {
+ throw new IllegalLinkException();
+ }
+ }
+
+ if (isset($_REQUEST['userID'])) {
+ $this->user = new UserEditor(intval($_REQUEST['userID']));
+
+ // validate user ID
+ if (!$this->user->userID) {
+ throw new IllegalLinkException();
+ }
+ }
+
+ if (isset($_REQUEST['token'])) {
+ $this->token = StringUtil::trim($_REQUEST['token']);
+
+ // validate token
+ if (empty($this->token) || $this->user->notificationMailToken != $this->token) {
+ throw new IllegalLinkException();
+ }
+ }
+
+ if (!$this->user || !$this->notification || !$this->token) {
+ throw new IllegalLinkException();
+ }
+ }
+
+ /**
+ * @see Action::execute()
+ */
+ public function execute() {
+ parent::execute();
+
+ // delete old entry if present
+ $sql = "DELETE FROM wcf".WCF_N."_user_notification_event_to_user
+ WHERE objectType = '".escapeString($this->notification->objectType)."'
+ AND eventName = '".escapeString($this->notification->eventName)."'
+ AND notificationType = 'mail'
+ AND enabled = 1
+ AND packageID = ".$this->notification->packageID."
+ AND userID = ".$this->user->userID;
+ WCF::getDB()->sendQuery($sql);
+
+ // insert new setting for this type
+ $sql = "INSERT INTO wcf".WCF_N."_user_notification_event_to_user
+ (userID, packageID, objectType, eventName, notificationType, enabled)
+ VALUES (".$this->user->userID.",
+ ".$this->notification->packageID.",
+ '".escapeString($this->notification->objectType)."',
+ '".escapeString($this->notification->eventName)."',
+ 'mail',
+ 0)";
+ WCF::getDB()->sendQuery($sql);
+
+ $this->executed();
+
+ WCF::getTPL()->assign(array(
+ 'url' => 'index.php'.SID_ARG_1ST,
+ 'message' => WCF::getLanguage()->get('wcf.user.notification.type.mail.disabled'),
+ 'wait' => 5
+ ));
+ WCF::getTPL()->display('redirect');
+ exit;
+ }
+
+}
+?>
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/system/session/UserSession.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationHandler.class.php');
+
+/**
+ * Represents a user in the notifications system
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage data.user
+ * @category Community Framework
+ */
+class NotificationUser extends UserSession {
+ /**
+ * True if the user's notification settings should be loaded
+ *
+ * @var boolean
+ */
+ protected $loadSettings = true;
+
+ /**
+ * Constructs a new NotificationUser object
+ *
+ * @param integer $userID
+ * @param mixed $row
+ * @param boolean $loadSettings
+ * @see UserSession::__construct
+ */
+ public function __construct($userID, $row = null, $loadSettings = true) {
+ if (is_object($row)) {
+ $row = $row->data;
+ }
+ $this->loadSettings = $loadSettings;
+
+ parent::__construct($userID, $row);
+ }
+
+ /**
+ * @see DatabaseObject::__construct
+ */
+ protected function handleData($data) {
+ if ($data['userID'] && $this->loadSettings) {
+ // load notification settings
+ $sql = "SELECT objectType, eventName, notificationType, enabled
+ FROM wcf".WCF_N."_user_notification_event_to_user
+ WHERE userID = ".$data['userID']."
+ AND packageID IN (".NotificationHandler::getAvailablePackageIDs().")";
+ $result = WCF::getDB()->sendQuery($sql);
+
+ $data['eventNotificationSettings'] = array();
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $data['eventNotificationSettings'][$row['objectType']][$row['eventName']][$row['notificationType']] = $row['enabled'];
+ }
+ }
+ if (isset($data['notificationFlags'])) {
+ $data['notificationFlags'] = unserialize($data['notificationFlags']);
+ }
+ parent::handleData($data);
+ }
+
+ /**
+ * Returns an array of notification types which are activated for the given
+ * event for this user
+ *
+ * @param string $eventName
+ * @param string $objectType
+ * @return array<mixed>
+ */
+ public function getEventNotificationTypes($eventName, $objectType) {
+ $notificationTypes = array();
+ if (isset($this->data['eventNotificationSettings'][$objectType][$eventName])) {
+ foreach ($this->data['eventNotificationSettings'][$objectType][$eventName] as $typeName => $enabled) {
+ if ($enabled) {
+ $notificationTypeObject = null;
+ try {
+ $notificationTypeObject = NotificationHandler::getNotificationTypeObject($typeName);
+ }
+ catch (SystemException $ex) {
+ continue;
+ }
+ $notificationTypes[] = $notificationTypeObject;
+ }
+ }
+ }
+ else {
+ $objectTypes = NotificationHandler::getAvailableNotificationObjectTypes();
+ $notificationTypeObject = null;
+ try {
+ $notificationTypeObject = NotificationHandler::getNotificationTypeObject($objectTypes[$objectType]['events'][$eventName]->defaultNotificationType);
+ $notificationTypes[] = $notificationTypeObject;
+ }
+ catch (SystemException $ex) {
+ // do nothing
+ }
+ }
+
+ return $notificationTypes;
+ }
+
+ /**
+ * Returns true if there are any unseen notifications for this user
+ *
+ * @return integer
+ */
+ public function hasOutstandingNotifications() {
+ $count = 0;
+
+ foreach (explode(',', NotificationHandler::getAvailablePackageIDs()) as $packageID) {
+ if (isset($this->data['notificationFlags'][$packageID]) && $this->data['notificationFlags'][$packageID] > 0) {
+ $count += $this->data['notificationFlags'][$packageID];
+ }
+ }
+
+ return $count;
+ }
+
+ /**
+ * Increases the notification counter for a notification object type
+ *
+ * @param integer $packageID
+ * @param integer $count
+ */
+ public function addOutstandingNotification($packageID, $count = 1) {
+ // validation
+ if ($count < 1) return;
+
+ if (isset($this->data['notificationFlags'][$packageID])) {
+ $this->data['notificationFlags'][$packageID] += $count;
+ }
+ else $this->data['notificationFlags'][$packageID] = $count;
+
+ $editor = $this->getEditor();
+ $editor->updateFields(array('notificationFlags' => serialize($this->data['notificationFlags'])));
+ Session::resetSessions(array($this->userID), true, false);
+ }
+
+ /**
+ * Decreases the notification counter for a notification object type
+ *
+ * @param integer $packageID
+ * @param integer $count
+ */
+ public function removeOutstandingNotification($packageID, $count = 1) {
+ // validation
+ if ($count < 1) return;
+
+ if (isset($this->data['notificationFlags'][$packageID])) {
+ $this->data['notificationFlags'][$packageID] -= $count;
+ // "thread" security
+ if ($this->data['notificationFlags'][$packageID] <= 0) {
+ unset($this->data['notificationFlags'][$packageID]);
+ }
+ }
+
+ $editor = $this->getEditor();
+ $editor->updateFields(array('notificationFlags' => serialize($this->data['notificationFlags'])));
+ Session::resetSessions(array($this->userID), true, false);
+ }
+
+ /**
+ * Recalculates all notification flags
+ */
+ public function recalculateOutstandingNotifications() {
+ self::recalculateUserNotificationFlags(array($this->userID));
+ }
+
+ /**
+ * Bulk processes a number of users and recalculates their notification flags
+ *
+ * @param array<integer> userIDs
+ */
+ public static function recalculateUserNotificationFlags($userIDs = array()) {
+ if (!count($userIDs)) return;
+ $sql = "SELECT COUNT(*) AS count, n.packageID, u.userID
+ FROM wcf".WCF_N."_user_notification n
+ LEFT JOIN
+ wcf".WCF_N."_user_notification_to_user u
+ ON n.notificationID = u.notificationID
+ WHERE u.userID IN(".implode(',', $userIDs).")
+ AND u.confirmed = 0
+ GROUP BY n.packageID, u.userID";
+ $result = WCF::getDB()->sendQuery($sql);
+
+ $notificationFlags = array();
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $notificationFlags[$row['userID']][$row['packageID']] = $row['count'];
+ }
+
+ $inserts = '';
+ // add empty data and prepare inserts
+ foreach ($userIDs as $userID) {
+ if (!isset($notificationFlags[$userID])) {
+ $notificationFlags[$userID] = array();
+ }
+
+ if (!empty($inserts)) $inserts .= ',';
+ $inserts .= "(".$userID.", '".escapeString(serialize($notificationFlags[$userID]))."')";
+ }
+
+ if (!empty($inserts)) {
+ $sql = "INSERT INTO wcf".WCF_N."_user
+ (userID, notificationFlags)
+ VALUES ".$inserts."
+ ON DUPLICATE KEY UPDATE notificationFlags = VALUES(notificationFlags)";
+ WCF::getDB()->sendQuery($sql);
+ }
+
+ Session::resetSessions($userIDs, true, false);
+ }
+
+ /**
+ * @see User::getEditor()
+ */
+ public function getEditor() {
+ // saves another query
+ require_once(WCF_DIR.'lib/data/user/UserEditor.class.php');
+ return new UserEditor(null, array_merge(get_object_vars($this), $this->data));
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/Notification.class.php');
+
+/**
+ * Represents a notification in a rss or atom feed
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class FeedNotification extends Notification {
+ /**
+ * @see Notification::handleData()
+ */
+ protected function handleData($data) {
+ // escape CDATA
+ $data['shortOutput'] = StringUtil::escapeCDATA(StringUtil::stripHTML($data['shortOutput']));
+ $data['mediumOutput'] = StringUtil::escapeCDATA($data['mediumOutput']);
+ $data['longOutput'] = StringUtil::escapeCDATA($data['longOutput']);
+ if (isset($data['messageCache'])) $data['messageCache'] = StringUtil::escapeCDATA($data['messageCache']);
+
+ parent::handleData($data);
+ }
+
+ /**
+ * @see Notification::parseURLsCallback()
+ */
+ protected function parseURLsCallback($match) {
+ $url = parent::parseURLsCallback($match);
+
+ $url = FileUtil::addTrailingSlash(PAGE_URL).$url;
+
+ return $url;
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/NotificationList.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/FeedNotification.class.php');
+
+/**
+ * Represents a list of feed notifications
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class FeedNotificationList extends NotificationList {
+ /**
+ * @see DatabaseObjectList::readObjects()
+ */
+ public function readObjects() {
+ // get ids
+ $notificationIDArray = $objectIDArray = $objects = array();
+ $notificationObjectTypes = NotificationHandler::getAvailableNotificationObjectTypes();
+ $sqlConditions = $this->sqlConditions;
+ if (!empty($sqlConditions)) $sqlConditions .= " AND ";
+ $sqlConditions .= "notification.packageID IN(".NotificationHandler::getAvailablePackageIDs().")";
+ $sql = "SELECT ".$this->sqlSelects." notification.*, GROUP_CONCAT(u.userID SEPARATOR ',') AS userID
+ FROM wcf".WCF_N."_user_notification notification
+ LEFT JOIN
+ wcf".WCF_N."_user_notification_to_user u
+ ON notification.notificationID = u.notificationID
+ ".$this->sqlJoins."
+ WHERE ".$sqlConditions."
+ GROUP BY notification.notificationID
+ ".(!empty($this->sqlOrderBy) ? "ORDER BY ".$this->sqlOrderBy : '');
+ $result = WCF::getDB()->sendQuery($sql, $this->sqlLimit, $this->sqlOffset);
+ while ($row = WCF::getDB()->fetchArray()) {
+ if (!isset($notificationObjectTypes[$row['objectType']]['events'][$row['eventName']])) continue;
+ $row['event'] = $notificationObjectTypes[$row['objectType']]['events'][$row['eventName']];
+ $this->notifications[] = new FeedNotification(null, $row);
+ }
+
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/Notification.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationHandler.class.php');
+require_once(WCF_DIR.'lib/data/DatabaseObjectList.class.php');
+
+/**
+ * Represents a list of notifications
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class NotificationList extends DatabaseObjectList {
+ // system
+ public $sqlOrderBy = 'notification.time DESC';
+
+ /**
+ * list of notifications
+ *
+ * @var array<Notification>
+ */
+ public $notifications = array();
+
+ /**
+ * @see DatabaseObjectList::countObjects()
+ */
+ public function countObjects() {
+ $sqlConditions = $this->sqlConditions;
+ if (!empty($sqlConditions)) $sqlConditions .= " AND ";
+ $sqlConditions .= "notification.packageID IN(".NotificationHandler::getAvailablePackageIDs().")";
+ $sql = "SELECT COUNT(*) AS count
+ FROM wcf".WCF_N."_user_notification notification
+ LEFT JOIN
+ wcf".WCF_N."_user_notification_to_user u
+ ON notification.notificationID = u.notificationID
+ WHERE ".$sqlConditions;
+ $row = WCF::getDB()->getFirstRow($sql);
+ return $row['count'];
+ }
+
+ /**
+ * @see DatabaseObjectList::readObjects()
+ */
+ public function readObjects() {
+ // get ids
+ $notificationIDArray = $objectIDArray = $objects = array();
+ $notificationObjectTypes = NotificationHandler::getAvailableNotificationObjectTypes();
+ $sqlConditions = $this->sqlConditions;
+ if (!empty($sqlConditions)) $sqlConditions .= " AND ";
+ $sqlConditions .= "notification.packageID IN(".NotificationHandler::getAvailablePackageIDs().")";
+ $sql = "SELECT ".$this->sqlSelects." notification.*, GROUP_CONCAT(u.userID SEPARATOR ',') AS userID
+ FROM wcf".WCF_N."_user_notification notification
+ LEFT JOIN
+ wcf".WCF_N."_user_notification_to_user u
+ ON notification.notificationID = u.notificationID
+ ".$this->sqlJoins."
+ WHERE ".$sqlConditions."
+ GROUP BY notification.notificationID
+ ".(!empty($this->sqlOrderBy) ? "ORDER BY ".$this->sqlOrderBy : '');
+ $result = WCF::getDB()->sendQuery($sql, $this->sqlLimit, $this->sqlOffset);
+ while ($row = WCF::getDB()->fetchArray()) {
+ if (!isset($notificationObjectTypes[$row['objectType']]['events'][$row['eventName']])) continue;
+ $row['event'] = clone $notificationObjectTypes[$row['objectType']]['events'][$row['eventName']];
+ $this->notifications[] = new Notification(null, $row);
+ }
+
+ }
+
+ /**
+ * @see DatabaseObjectList::getObjects()
+ */
+ public function getObjects() {
+ return $this->notifications;
+ }
+}
+?>
--- /dev/null
+<?php
+namespace wcf\data\user\notification;
+use wcf\data\DatabaseObject;
+
+/**
+ * Represents a user notification.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class UserNotification extends DatabaseObject {
+ /**
+ * @see DatabaseObject::$databaseTableName
+ */
+ protected static $databaseTableName = 'user_notification';
+
+ /**
+ * @see DatabaseObject::$databaseTableIndexName
+ */
+ protected static $databaseTableIndexName = 'notificationID';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification;
+use wcf\data\AbstractDatabaseObjectAction;
+
+/**
+ * Executes user notification-related actions.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class UserNotificationAction extends AbstractDatabaseObjectAction {
+ /**
+ * @see AbstractDatabaseObjectAction::$className
+ */
+ protected $className = 'wcf\data\user\notification\UserNotificationEditor';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification;
+use wcf\data\DatabaseObjectEditor;
+
+/**
+ * Provides functions to edit user notifications.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class UserNotificationEditor extends DatabaseObjectEditor {
+ /**
+ * @see DatabaseObjectEditor::$baseClass
+ */
+ protected static $baseClass = 'wcf\data\user\notification\UserNotification';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/NotificationUser.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/UserNotificationEditor.class.php');
+
+/**
+ * The core class of the notification system
+ *
+ * @author Marcel Werk, Tim Duesterhus, Oliver Kliebisch
+ * @copyright 2009-2011 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class UserNotificationHandler {
+ /**
+ * list of available notification object types
+ * @var array<UserNotificationObjectType>
+ */
+ public static $availableNotificationObjectTypes = null;
+
+ /**
+ * list of available notification types
+ * @var array<UserNotificationType>
+ */
+ public static $availableNotificationTypes = null;
+
+ /**
+ * available notification object package IDs
+ * @var array<integer>
+ */
+ protected static $availableNotificationObjectIDs = null;
+
+ /**
+ * notification cache data
+ * @var array<mixed>
+ */
+ protected static $cacheData = null;
+
+ /**
+ * The reference user object for the permission check
+ * @var User
+ */
+ protected static $user = null;
+
+ /**
+ * Triggers a notification event
+ *
+ * @param string $eventName
+ * @param string $objectType
+ * @param mixed $notificationObject
+ * @param integer $recipientUserID
+ * @param array<mixed> $additionalData
+ */
+ public static function fireEvent($eventName, $objectType, $notificationObject, $recipientUserID, $additionalData = array()) {
+ if (!MODULE_USER_NOTIFICATION) return;
+ // get recipient and apply it to the handler
+ $recipient = new NotificationUser($recipientUserID);
+ if ($recipient->userID == 0) return;
+ self::setUser($recipient);
+
+ $objectTypes = self::getAvailableNotificationObjectTypes();
+ if (isset($objectTypes[$objectType]['events'][$eventName])) {
+ $objectTypeObject = $objectTypes[$objectType]['object'];
+ $eventObject = $objectTypes[$objectType]['events'][$eventName];
+
+ // save memory
+ unset ($objectTypes);
+
+ // fetches the notification object if $notificationObject isn't already one
+ if (!$notificationObject instanceof UserNotificationConveyableObject) {
+ $notificationObject = $objectTypeObject->getObjects($notificationObject);
+ $notificationObject = current($notificationObject);
+ }
+
+ if (!$notificationObject) {
+ throw new SystemException("Unable to fetch the notification object with the type '".$objectType."'", 11000);
+ }
+ $eventObject->setObject($notificationObject, $additionalData);
+
+ // get notification types
+ $notificationTypes = $recipient->getEventNotificationTypes($eventName, $objectType);
+
+ // switch to recipient language
+ // enable recipient language
+ $languages = array(0 => WCF::getLanguage(), WCF::getLanguage()->getLanguageID() => WCF::getLanguage());
+ if (!isset($languages[$recipient->languageID])) $languages[$recipient->languageID] = new Language($recipient->languageID);
+ $languages[$recipient->languageID]->setLocale();
+ $eventObject->setLanguage($languages[$recipient->languageID]);
+
+ // prepare messages and send notification messages
+ $notification = UserNotificationEditor::create(array(
+ 'userID' => $recipient->userID,
+ 'packageID' => $objectTypeObject->getPackageID(),
+ 'objectType' => $objectType,
+ 'objectID' => $notificationObject->getObjectID(),
+ 'eventName' => $eventName,
+ 'time' => TIME_NOW,
+ 'shortOutput' => $eventObject->getShortOutput($eventName),
+ 'mediumOutput' => $eventObject->getMediumOutput($eventName),
+ 'longOutput' => $eventObject->getOutput($eventName),
+ 'additionalData' => $additionalData
+ ));
+
+ foreach ($notificationTypes as $notificationType) {
+ if ($eventObject->supportsNotificationType($notificationType) == false) {
+ continue;
+ }
+
+ $notificationType->send($recipient, $eventObject, $notification);
+ }
+
+ // add notification flag
+ $recipient->addOutstandingNotification(self::getNotificationObjectTypeObject($notification->objectType)->getPackageID());
+
+ // enable user language
+ WCF::getLanguage()->setLocale();
+ }
+ }
+
+ /**
+ * Revokes an event and all its messages if possible
+ *
+ * @param array<string> $eventName
+ * @param string $objectType
+ * @param mixed $notificationObject
+ * @param array<mixed> $additionalData
+ */
+ public static function revokeEvent($eventNames, $objectType, $notificationObjects, $additionalData = array()) {
+ $objectTypes = self::getAvailableNotificationObjectTypes();
+ $objectTypeObject = $objectTypes[$objectType]['object'];
+ $eventObjectArray = array();
+ foreach ($eventNames as $key => $eventName) {
+ if (isset($objectTypes[$objectType]['events'][$eventName])) {
+ $eventObjectArray[$eventName] = $objectTypes[$objectType]['events'][$eventName];
+ }
+ else {
+ unset($eventNames[$key]);
+ }
+ }
+
+ unset($objectTypes);
+
+ // fetches the notification objects
+ $notificationObjects = $objectTypeObject->getObjects($notificationObjects);
+
+ if (!count($notificationObjects)) {
+ throw new SystemException("Unable to fetch the notification object with the type '".$objectType."'", 11000);
+ }
+ $objectIDArray = array();
+ foreach ($notificationObjects as $notificationObject) {
+ $objectIDArray[] = $notificationObject->getObjectID();
+ }
+
+ $sql = "SELECT n.*,
+ GROUP_CONCAT(u.userID SEPARATOR ',') AS userID
+ FROM wcf".WCF_N."_user_notification n
+ LEFT JOIN
+ wcf".WCF_N."_user_notification_to_user u
+ ON n.notificationID = u.notificationID
+ WHERE objectType = '".escapeString($objectType)."'
+ AND packageID = ".$objectTypeObject->getPackageID()."
+ AND objectID IN(".implode(',', $objectIDArray).")
+ AND eventName IN('".implode("','", array_map('escapeString', $eventNames))."')";
+ $result = WCF::getDB()->getResultList($sql);
+ if ($result[0]['notificationID'] === null) return;
+ $affectedUserIDs = array();
+ $notificationIDArray = array();
+ foreach ($result as $row) {
+ $notification = new UserNotificationEditor(null, $row);
+ $notificationIDArray[] = $notification->notificationID;
+ $row['userID'] = explode(',', $row['userID']);
+ $recipients = array();
+ foreach ($row['userID'] as $userID) {
+ // could we do it better?
+ $recipients[] = new UserNotificationUser($userID, null, false);
+ }
+
+ $eventObject = $eventObjectArray[$notification->eventName];
+ $notificationObject = $notificationObjects[$notification->objectID];
+ $eventObject->setObject($notificationObject, $additionalData);
+ foreach ($recipients as $recipient) {
+ $notificationTypeArray = UserNotificationHandler::getAvailableNotificationObjectTypes();
+ foreach ($notificationTypeArray as $notificationType) {
+ $notificationTypeObject = null;
+ try {
+ $notificationTypeObject = self::getNotificationTypeObject($notificationType);
+ if (!$notificationTypeObject) continue;
+ }
+ catch (SystemException $ex) {
+ // notification object might be missing but that would be no error
+ continue;
+ }
+ // revoke messages if supported
+ $notificationTypeObject->revoke($recipient, $eventObject, $notification);
+ }
+
+ $affectedUserIDs[] = $recipient->userID;
+ }
+ }
+
+ // delete notification data
+ UserNotificationEditor::deleteAll($notificationIDArray);
+
+ // update user flags
+ UserNotificationUser::recalculateUserNotificationFlags($affectedUserIDs);
+ }
+
+ /**
+ * Gets notification objects by their ids.
+ *
+ * @param string $objectType
+ * @param mixed $objectID
+ * @return mixed
+ */
+ public static function getNotificationObjectByID($objectType, $objectID) {
+ // get notification object type object
+ $typeObject = null;
+ try {
+ $typeObject = self::getNotificationObjectTypeObject($objectType);
+ }
+ catch (SystemException $e) {
+ return null;
+ }
+
+ // get notification objects
+ return $typeObject->getObjectByID($objectID);
+ }
+
+ /**
+ * Returns the object of a notification object type.
+ *
+ * @param string $objectType
+ * @return NotificationObjectType
+ */
+ public static function getNotificationObjectTypeObject($objectType) {
+ $types = self::getAvailableNotificationObjectTypes();
+ if (!isset($types[$objectType])) {
+ throw new SystemException("Unknown notification object type '".$objectType."'", 11000);
+ }
+
+ return $types[$objectType]['object'];
+ }
+
+ /**
+ * Returns the object of a notification type.
+ *
+ * @param string $notificationType
+ * @return NotificationType
+ */
+ public static function getNotificationTypeObject($notificationType) {
+ $types = self::getAvailableNotificationTypes();
+ if (!isset($types[$notificationType])) {
+ throw new SystemException("Unknown notification object type '".$notificationType."'", 11000);
+ }
+
+ return $types[$notificationType];
+ }
+
+ /**
+ * Returns a list of available notification object types.
+ *
+ * @return array<NotificationObjectType>
+ */
+ public static function getAvailableNotificationObjectTypes() {
+ if (self::$availableNotificationObjectTypes === null) {
+ self::loadCache();
+ $types = self::$cacheData['objectTypes'];
+ foreach ($types as $type) {
+ // check options and modules
+ if (!empty($type['options'])) {
+ $options = explode(',', StringUtil::toUpperCase($type['options']));
+ foreach ($options as $option) {
+ if (!defined($option) || !constant($option))
+ continue 2;
+ }
+ }
+
+ // check permissions
+ if (!empty($type['permissions'])) {
+ $permissions = explode(',', $type['permissions']);
+ foreach ($permissions as $permission) {
+ if (!self::getUser()->getPermission($permission))
+ continue 2;
+ }
+ }
+
+ // get path to class file
+ if (empty($type['packageDir'])) {
+ $path = WCF_DIR;
+ }
+ else {
+ $path = FileUtil::getRealPath(WCF_DIR.$type['packageDir']);
+ }
+ $path .= $type['classFile'];
+
+ // include class file
+ if (!class_exists($type['className'])) {
+ if (!file_exists($path)) {
+ throw new SystemException("Unable to find class file '".$path."'", 11000);
+ }
+ require_once($path);
+ }
+
+ // instance object
+ if (!class_exists($type['className'])) {
+ throw new SystemException("Unable to find class '".$type['className']."'", 11001);
+ }
+ self::$availableNotificationObjectTypes[$type['objectType']]['object'] = new $type['className'];
+ }
+
+ $events = self::$cacheData['events'];
+ foreach ($events as $event) {
+ // check options and modules
+ if (!empty($event['options'])) {
+ $options = explode(',', StringUtil::toUpperCase($event['options']));
+ foreach ($options as $option) {
+ if (!defined($option) || !constant($option))
+ continue 2;
+ }
+ }
+
+ // check permissions
+ if (!empty($event['permissions'])) {
+ $permissions = explode(',', $event['permissions']);
+ foreach ($permissions as $permission) {
+ if (!self::getUser()->getPermission($permission))
+ continue 2;
+ }
+ }
+
+ // get path to class file
+ if (empty($event['packageDir'])) {
+ $path = WCF_DIR;
+ }
+ else {
+ $path = FileUtil::getRealPath(WCF_DIR.$event['packageDir']);
+ }
+ $path .= $event['classFile'];
+
+ // include class file
+ if (!class_exists($event['className'])) {
+ if (!file_exists($path)) {
+ // load default event
+ require_once(WCF_DIR.'lib/data/user/notification/event/DefaultNotificationEvent.class.php');
+ $event['className'] = 'DefaultNotificationEvent';
+ //throw new SystemException("Unable to find class file '".$path."'", 11000);
+ }
+ else require_once($path);
+ }
+
+ // instance object
+ if (!class_exists($event['className'])) {
+ throw new SystemException("Unable to find class '".$event['className']."'", 11001);
+ }
+ self::$availableNotificationObjectTypes[$event['objectType']]['events'][$event['eventName']] = new $event['className']($event);
+ }
+ }
+
+ return self::$availableNotificationObjectTypes;
+ }
+
+ /**
+ * Returns a list of available notification types
+ *
+ * @return array<NotificationType>
+ */
+ public static function getAvailableNotificationTypes() {
+ if (self::$availableNotificationTypes === null) {
+ self::loadCache();
+ $types = self::$cacheData['notificationTypes'];
+ foreach ($types as $type) {
+ // check options and modules
+ if (!empty($type['options'])) {
+ $options = explode(',', StringUtil::toUpperCase($type['options']));
+ foreach ($options as $option) {
+ if (!defined($option) || !constant($option))
+ continue 2;
+ }
+ }
+
+ // check permissions
+ if (!empty($type['permissions'])) {
+ $permissions = explode(',', $type['permissions']);
+ foreach ($permissions as $permission) {
+ if (!self::getUser()->getPermission($permission))
+ continue 2;
+ }
+ }
+
+ // get path to class file
+ if (empty($type['packageDir'])) {
+ $path = WCF_DIR;
+ }
+ else {
+ $path = FileUtil::getRealPath(WCF_DIR.$type['packageDir']);
+ }
+ $path .= $type['classFile'];
+
+ // include class file
+ if (!class_exists($type['className'])) {
+ if (!file_exists($path)) {
+ throw new SystemException("Unable to find class file '".$path."'", 11000);
+ }
+ require_once($path);
+ }
+
+ // instance object
+ if (!class_exists($type['className'])) {
+ throw new SystemException("Unable to find class '".$type['className']."'", 11001);
+ }
+ self::$availableNotificationTypes[$type['notificationType']] = new $type['className'];
+ }
+ }
+
+ return self::$availableNotificationTypes;
+ }
+
+ /**
+ * Returns a concatenized string of available package IDs
+ *
+ * @return string
+ */
+ public static function getAvailablePackageIDs() {
+ if (self::$availableNotificationObjectIDs === null) {
+ $objectTypeObjects = self::getAvailableNotificationObjectTypes();
+
+ self::$availableNotificationObjectIDs = array();
+ if ($objectTypeObjects) {
+ foreach ($objectTypeObjects as $objectType) {
+ if ($packageID = $objectType['object']->getPackageID()) {
+ self::$availableNotificationObjectIDs[] = $packageID;
+ }
+
+ $additionalPackageIDs = $objectType['object']->getAdditionalPackageIDs();
+ if (!empty($additionalPackageIDs)) {
+ self::$availableNotificationObjectIDs = array_merge($additionalPackageIDs, self::$availableNotificationObjectIDs);
+ }
+ }
+ }
+
+ array_unique(self::$availableNotificationObjectIDs);
+ }
+
+ return count(self::$availableNotificationObjectIDs) ? '0,'.implode(',', self::$availableNotificationObjectIDs) : '0';
+ }
+
+ /**
+ * Sets the user for permission checks
+ *
+ * @param UserSession $user
+ */
+ public static function setUser(UserSession $user) {
+ self::$user = $user;
+ self::$availableNotificationObjectTypes = self::$availableNotificationTypes = self::$availableNotificationObjectIDs = null;
+ }
+
+ /**
+ * Returns the user for permission checks
+ *
+ * @return UserSession
+ */
+ public static function getUser() {
+ if (self::$user === null || !self::$user instanceof UserSession) {
+ self::$user = WCF::getUser();
+ }
+
+ return self::$user;
+ }
+
+ /**
+ * Loads the notification cache
+ */
+ protected static function loadCache() {
+ if (self::$cacheData === null) {
+ WCF::getCache()->addResource('notifications-'.PACKAGE_ID, WCF_DIR.'cache/cache.notifications-'.PACKAGE_ID.'.php', WCF_DIR.'lib/system/cache/CacheBuilderNotifications.class.php');
+ self::$cacheData = WCF::getCache()->get('notifications-'.PACKAGE_ID);
+ }
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of user notifications.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class UserNotificationList extends DatabaseObjectList {
+ /**
+ * @see DatabaseObjectList::$className
+ */
+ public $className = 'wcf\data\user\notification\UserNotification';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/system/template/TemplateScriptingCompiler.class.php');
+
+/**
+ * Compiles template scripting in notification messages.
+ *
+ * @author Marcel Werk, Oliver Kliebisch
+ * @copyright 2009-2011 WoltLab GmbH, Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class UserNotificationMessageCompiler extends TemplateScriptingCompiler {
+ public $rightDelimiter = '}}';
+ public $leftDelimiter = '{{';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf import
+require_once(WCF_DIR.'lib/data/user/notification/event/UserNotificationConveyableEvent.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/event/UserNotificationEvent.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/object/UserNotificationConveyableObject.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/UserNotification.class.php');
+
+/**
+ * This is the default and simple notification event class if you don't need further customization
+ *
+ * @author Marcel Werk, Oliver Kliebisch
+ * @copyright 2009-2010 WoltLab GmbH, Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.event
+ * @category Community Framework
+ */
+class DefaultUserNotificationConveyableEvent implements UserNotificationConveyableEvent {
+ /**
+ * notification event
+ *
+ * @var UserNotificationEvent
+ */
+ protected $event = null;
+
+ /**
+ * The language object of the recipient user's language
+ *
+ * @var Language
+ */
+ protected $language = null;
+
+ /**
+ * The notification object
+ *
+ * @var UserNotificationConveyableObject
+ */
+ protected $object = null;
+
+ /**
+ * Additional data for this event
+ *
+ * @var array<mixed>
+ */
+ public $additionalData = array();
+
+ /**
+ * Creates a new DefaultUserNotificationConveyableEvent object.
+ *
+ * @param UserNotificationEvent $event
+ */
+ public function __construct(UserNotificationEvent $event) {
+ $this->event = $event;
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::initialize()
+ */
+ public function initialize(&$data) {
+ return;
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getMessage()
+ */
+ public function getMessage(NotificationType $notificationType, $additionalVariables = array()) {
+ return $this->getLanguageVariable($this->event->languageCategory.'.'.$this->getEventName().'.'.$notificationType->getName(), $additionalVariables);
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getShortOutput()
+ */
+ public function getShortOutput() {
+ return $this->getLanguageVariable($this->event->languageCategory.'.'.$this->getEventName().'.short');
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getMediumOutput()
+ */
+ public function getMediumOutput() {
+ return $this->getLanguageVariable($this->event->languageCategory.'.'.$this->getEventName().'.medium');
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getShortOutput()
+ */
+ public function getOutput() {
+ return $this->getLanguageVariable($this->event->languageCategory.'.'.$this->getEventName());
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getTitle()
+ */
+ public function getTitle() {
+ return $this->getLanguageVariable($this->event->languageCategory.'.'.$this->getEventName().'.title');
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getDescription()
+ */
+ public function getDescription() {
+ return $this->getLanguageVariable($this->event->languageCategory.'.'.$this->getEventName().'.description');
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getLanguageVariable()
+ */
+ public function getLanguageVariable($var, $additionalVariables = array()) {
+ return $this->getLanguage()->getDynamicVariable($var, array_merge($additionalVariables,
+ array(
+ 'event' => $this
+ )
+ ));
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::supportsNotificationType()
+ */
+ public function supportsNotificationType(NotificationType $notificationType) {
+ // returns true if the language variable exists. By using the
+ // static getter, errors are avoided
+ return ($this->getLanguage()->get($this->event->languageCategory.'.'.$this->getEventName().'.'.$notificationType->getName()) != $this->event->languageCategory.'.'.$this->getEventName().'.'.$notificationType->getName());
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getLanguage()
+ */
+ public function getLanguage() {
+ if ($this->language === null || !$this->language instanceof Language) {
+ $this->language = WCF::getLanguage();
+ }
+
+ return $this->language;
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::setLanguage()
+ */
+ public function setLanguage(Language $language) {
+ $this->language = $language;
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getObject()
+ */
+ public function getObject() {
+ return $this->object;
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::setObject()
+ */
+ public function setObject(UserNotificationConveyableObject $object, $additionalData = array()) {
+ $this->object = $object;
+ $this->additionalData = $additionalData;
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getEventName()
+ */
+ public function getEventName() {
+ return $this->event->eventName;
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getIcon()
+ */
+ public function getIcon() {
+ return $this->event->icon;
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getAcceptURL()
+ */
+ public function getAcceptURL(UserNotification $notification) {
+ if ($this->event->requiresConfirmation) {
+ if ($this->event->acceptURL) {
+ return $this->parseURL($this->event->acceptURL, $notification);
+ }
+ else {
+ return $this->parseURL('index.php?action=NotificationConfirm¬ificationID='.$notification->notificationID, $notification);
+ }
+ }
+ else {
+ return '';
+ }
+ }
+
+ /**
+ * @see UserNotificationConveyableEvent::getDeclineURL()
+ */
+ public function getDeclineURL(UserNotification $notification) {
+ if ($this->event->requiresConfirmation && $this->event->declineURL) {
+ return $this->parseURL($this->event->declineURL, $notification);
+ }
+ else {
+ return '';
+ }
+ }
+
+ /**
+ * Parses accept and decline URLs
+ *
+ * @param string $url
+ * @param UserNotification $notification
+ * @return string
+ */
+ protected function parseURL($url, UserNotification $notification) {
+ $url = str_replace('%u', $notification->userID, $url);
+ $url = str_replace('%o', $notification->objectID, $url);
+ $url = str_replace('%n', $notification->notificationID, $url);
+
+ // append request uri
+ if (WCF::getSession()->requestMethod == 'GET') {
+ if (StringUtil::indexOf($url, '?') !== false) {
+ $url .= '&';
+ }
+ else {
+ $url .= '?';
+ }
+ preg_match('/index\.php.*/is', WCF::getSession()->requestURI, $requestURI);
+
+ $url .= 'url='.rawurlencode($requestURI[0]);
+ }
+
+ // append security token
+ $url .= '&t='.SECURITY_TOKEN;
+
+ // append session id
+ if (SID != '' && !preg_match('/(?:&|\?)s=[a-z0-9]{40}/', $url)) {
+ if (StringUtil::indexOf($url, '?') !== false) {
+ $url .= SID_ARG_2ND_NOT_ENCODED;
+ }
+ else {
+ $url .= SID_ARG_1ST;
+ }
+ }
+
+ return $url;
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/UserNotification.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/type/NotificationType.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/object/UserNotificationConveyableObject.class.php');
+
+/**
+ * This interface should be implemented by every event which is fired by the notification system
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.event
+ * @category Community Framework
+ */
+interface UserNotificationConveyableEvent {
+ /**
+ * Callback function for event based data manipulation for notifications
+ *
+ * @param array<mixed> $data
+ */
+ public function initialize(&$data);
+
+ /**
+ * Returns the message for this notification event.
+ *
+ * @param NotificationType $notificationType
+ * @return string
+ */
+ public function getMessage(NotificationType $notificationType);
+
+ /**
+ * Returns the short output for this notification event
+ *
+ * @return string
+ */
+ public function getShortOutput();
+
+ /**
+ * Returns the medium output for this notification event
+ *
+ * @return string
+ */
+ public function getMediumOutput();
+
+ /**
+ * Returns the full output for this notification event
+ *
+ * @return string
+ */
+ public function getOutput();
+
+ /**
+ * Returns the human-readable title of this event
+ *
+ * @return string
+ */
+ public function getTitle();
+
+ /**
+ * Returns the human-readable description of this event
+ *
+ * @return string
+ */
+ public function getDescription();
+
+ /**
+ * Returns the icon of this event
+ *
+ * @return string
+ */
+ public function getIcon();
+
+ /**
+ *
+ * @param string $var
+ * @param array<mixed> $additionalVariables
+ */
+ public function getLanguageVariable($var, $additionalVariables = array());
+
+ /**
+ * Returns true if this event supports the given notification type
+ *
+ * @param NotificationType $notificationType
+ * @return boolean
+ */
+ public function supportsNotificationType(NotificationType $notificationType);
+
+ /**
+ * Sets the recipient user's language
+ *
+ * @param Language $language
+ */
+ public function setLanguage(Language $language);
+
+ /**
+ * Returns the recipient user's language
+ *
+ * @return Language
+ */
+ public function getLanguage();
+
+ /**
+ * Sets the object for the event
+ *
+ * @param UserNotificationConveyableObject $object
+ * @param array<mixed> $additionalData
+ */
+ public function setObject(UserNotificationConveyableObject $object, $additionalData = array());
+
+ /**
+ * Returns the object of this event
+ *
+ * @return NotificationObject
+ */
+ public function getObject();
+
+ /**
+ * Returns the name of this event
+ *
+ * @deprecated
+ * @return string
+ */
+ public function getEventName();
+
+ /**
+ * Returns the URL for accepting the notification
+ *
+ * @param UserNotification $notification
+ * @return string
+ */
+ public function getAcceptURL(UserNotification $notification);
+
+ /**
+ * Returns the URL for declining the notification
+ *
+ * @param UserNotification $notification
+ * @return string
+ */
+ public function getDeclineURL(UserNotification $notification);
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\event;
+use wcf\data\DatabaseObject;
+
+/**
+ * Represents a user notification event.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.event
+ * @category Community Framework
+ */
+class UserNotificationEvent extends DatabaseObject {
+ /**
+ * @see DatabaseObject::$databaseTableName
+ */
+ protected static $databaseTableName = 'user_notification_event';
+
+ /**
+ * @see DatabaseObject::$databaseTableIndexName
+ */
+ protected static $databaseTableIndexName = 'eventID';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\event;
+use wcf\data\AbstractDatabaseObjectAction;
+
+/**
+ * Executes user notification event-related actions.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.event
+ * @category Community Framework
+ */
+class UserNotificationEventAction extends AbstractDatabaseObjectAction {
+ /**
+ * @see AbstractDatabaseObjectAction::$className
+ */
+ protected $className = 'wcf\data\user\notification\event\UserNotificationEventEditor';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\event;
+use wcf\data\DatabaseObjectEditor;
+
+/**
+ * Provides functions to edit user notification events.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.event
+ * @category Community Framework
+ */
+class UserNotificationEventEditor extends DatabaseObjectEditor {
+ /**
+ * @see DatabaseObjectEditor::$baseClass
+ */
+ protected static $baseClass = 'wcf\data\user\notification\event\UserNotificationEvent';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\event;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of user notification events.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.event
+ * @category Community Framework
+ */
+class UserNotificationEventList extends DatabaseObjectList {
+ /**
+ * @see DatabaseObjectList::$className
+ */
+ public $className = 'wcf\data\user\notification\event\UserNotificationEvent';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/DatabaseObject.class.php');
+
+/**
+ * Represents a notification message.
+ *
+ * @author Marcel Werk
+ * @copyright 2009-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.message
+ * @category Community Framework
+ */
+class UserNotificationMessage extends DatabaseObject {
+ /**
+ * @see DatabaseObject::$databaseTableName
+ */
+ public $databaseTableName = 'user_notification_message';
+
+ /**
+ * @see DatabaseObject::$databaseIndexName
+ */
+ public $databaseIndexName = 'messageID';
+
+ /**
+ * Returns a notification message based on the given parameters.
+ *
+ * @param integer $notificationID
+ * @param string $notificationType
+ * @return UserNotificationMessage
+ */
+ public static function getMessage($notificationID, $notificationType) {
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_user_notification_message
+ WHERE notificationID = ".$notificationID."
+ AND notificationType = '".escapeString($notificationType)."'";
+ if (($row = WCF::getDB()->getFirstRow($sql)) === false) {
+ $row = array();
+ }
+
+ return new UserNotificationMessage(null, $row);
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/DatabaseObjectEditor.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/message/UserNotificationMessage.class.php');
+
+/**
+ * Extends the notification message object with functions to create, update and delete messages.
+ *
+ * @author Marcel Werk
+ * @copyright 2009-2010 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.message
+ * @category Community Framework
+ */
+class UserNotificationMessageEditor extends DatabaseObjectEditor {
+ /**
+ * @see DatabaseObjectEditor::$baseClass
+ */
+ protected static $baseClass = 'UserNotificationMessage';
+
+ /**
+ * @see EditableObject::create()
+ */
+ public static function create(array $parameters = array()) {
+ return self::__create('wcf'.WCF_N.'_user_notification_message', 'messageID', 'UserNotificationMessage', $parameters);
+ }
+
+ /**
+ * @see EditableObject::deleteAll()
+ */
+ public static function deleteAll(array $messageIDs = array()) {
+ return self::__deleteAll('wcf'.WCF_N.'_user_notification_message', 'messageID', $messageIDs);
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/object/UserNotificationConveyableObjectType.class.php');
+
+/**
+ * A default implementation for NotificationObjectType to provide access to NotificationObjects
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.object
+ * @category Community Framework
+ */
+abstract class AbstractUserNotificationConveyableObjectType implements UserNotificationConveyableObjectType {
+ /**
+ * @see NotficiationObjectType::getObjects()
+ */
+ public function getObjects($data) {
+ $objectArray = array();
+ if (is_int($data) || is_string($data)) {
+ $object = $this->getObjectByID($data);
+ if ($object) $objectArray[$object->getObjectID()] = $object;
+ }
+ else if (is_array($data)) {
+ $objectArray = $this->getObjectsByIDArray($data);
+ }
+ else if (is_object($data)) {
+ $object = $this->getObjectByObject($data);
+ if ($object) $objectArray[$object->getObjectID()] = $object;
+ }
+
+ return $objectArray;
+ }
+
+ /**
+ * @see NotficiationObjectType::getAdditionalPackageIDs()
+ */
+ public function getAdditionalPackageIDs() {
+ return array();
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * This interface should be implemented by every object which is part of a notification
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.object
+ * @category Community Framework
+ */
+interface UserNotificationConveyableObject {
+ /**
+ * Returns the ID of this object.
+ *
+ * @return string
+ */
+ public function getObjectID();
+
+ /**
+ * Returns the title of this object.
+ *
+ * @return string
+ */
+ public function getTitle();
+
+ /**
+ * Returns the url of this object.
+ *
+ * @return string
+ */
+ public function getURL();
+
+ /**
+ * Returns the icon of this object.
+ *
+ * @return string
+ */
+ public function getIcon();
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/object/UserNotificationConveyableObject.class.php');
+
+/**
+ * This interface defines the basic methods every notification object type should implement.
+ *
+ * @author Marcel Werk, Oliver Kliebisch
+ * @copyright 2009-2011 WoltLab GmbH, Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.object
+ * @category Community Framework
+ */
+interface UserNotificationConveyableObjectType {
+ /**
+ * Get the notification object by its ID
+ *
+ * @param integer $objectID
+ * @return UserNotificationConveyableObject
+ */
+ public function getObjectByID($objectID);
+
+ /**
+ * Get the notification object by using its parent object
+ *
+ * @param object $object
+ * @return UserNotificationConveyableObject
+ */
+ public function getObjectByObject($object);
+
+ /**
+ * Get the notification objects by their IDs
+ *
+ * @param array<integer> $objectIDs
+ * @return array<UserNotificationConveyableObject>
+ */
+ public function getObjectsByIDs(array $objectIDs);
+
+ /**
+ * Get the notification objects
+ *
+ * @param mixed $data
+ * @return array<UserNotificationConveyableObject>
+ */
+ public function getObjects($data);
+
+ /**
+ * Returns the package ID of the object's package
+ * It does not return the package ID of the oject type package
+ *
+ * @return integer
+ */
+ public function getPackageID();
+
+ /**
+ * Returns additional packageIDs.
+ * This can be used for multiple combined dependency trees
+ *
+ * @return array<integer>
+ */
+ public function getAdditionalPackageIDs();
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/DatabaseObject.class.php');
+
+/**
+ * Represents a notification object type.
+ *
+ * @author Marcel Werk
+ * @copyright 2009-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.object
+ * @category Community Framework
+ */
+class UserNotificationObjectType extends DatabaseObject {
+ /**
+ * @see DatabaseObject::$databaseTableName
+ */
+ public $databaseTableName = 'user_notification_object_type';
+
+ /**
+ * @see DatabaseObject::$databaseIndexName
+ */
+ public $databaseIndexName = 'objectTypeID';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/DatabaseObjectEditor.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/object/UserNotificationObjectType.class.php');
+
+/**
+ * Extends the notification object type object with functions to create, update and delete messages.
+ *
+ * @author Marcel Werk
+ * @copyright 2009-2010 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.object
+ * @category Community Framework
+ */
+class UserNotificationObjectTypeEditor extends DatabaseObjectEditor {
+ /**
+ * @see DatabaseObjectEditor::$baseClass
+ */
+ protected static $baseClass = 'UserNotificationObjectType';
+
+ /**
+ * @see EditableObject::create()
+ */
+ public static function create(array $parameters = array()) {
+ return self::__create('wcf'.WCF_N.'_user_notification_object_type', 'objectTypeID', 'UserNotificationObjectType', $parameters);
+ }
+
+ /**
+ * @see EditableObject::deleteAll()
+ */
+ public static function deleteAll(array $objectTypeIDs = array()) {
+ return self::__deleteAll('wcf'.WCF_N.'_user_notification_object_type', 'objectTypeID', $$objectTypeIDs);
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/object/UserNotificationConveyableObject.class.php');
+
+/**
+ * This dummy object provides the usage of object-unbound notifications
+ *
+ * @author Marcel Werk, Oliver Kliebisch
+ * @copyright 2009-2011 WoltLab GmbH, Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.object
+ * @category Community Framework
+ */
+class VoidUserNotificationConveyableObject implements UserNotificationConveyableObject {
+ /**
+ * @see UserNotificationConveyableObject::getIcon()
+ */
+ public function getIcon() {
+ return '';
+ }
+
+ /**
+ * @see UserNotificationConveyableObject::getObjectID()
+ */
+ public function getObjectID() {
+ return 0;
+ }
+
+ /**
+ * @see UserNotificationConveyableObject::getTitle()
+ */
+ public function getTitle() {
+ return '';
+ }
+
+ /**
+ * @see UserNotificationConveyableObject::getURL()
+ */
+ public function getURL() {
+ return '';
+ }
+}
+?>
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/object/AbstractUserNotificationConveyableObjectType.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/object/VoidUserNotificationConveyableObject.class.php');
+
+/**
+ * A notification object type for general unbound notifications
+ *
+ * @author Marcel Werk, Oliver Kliebisch
+ * @copyright 2009-2011 WoltLab GmbH, Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.object
+ * @category Community Framework
+ */
+class VoidUserNotificationConveyableObjectType extends AbstractUserNotificationConveyableObjectType {
+ /**
+ * @see UserNotificationConveyableObjectType::getObjectByID()
+ */
+ public function getObjectByID($objectID) {
+ return new VoidUserNotificationConveyableObject();
+ }
+
+ /**
+ * @see UserNotificationConveyableObjectType::getObjectByObject()
+ */
+ public function getObjectByObject($object) {
+ return new VoidUserNotificationConveyableObject();
+ }
+
+ /**
+ * @see UserNotificationConveyableObjectType::getObjectsByIDs()
+ */
+ public function getObjectsByIDs(array $objectIDs) {
+ return array(0 => new VoidUserNotificationConveyableObject());
+ }
+
+ /**
+ * @see UserNotificationConveyableObjectType::getPackageID()
+ */
+ public function getPackageID() {
+ // void notifications are bound directly to the notification package
+ return WCF::getPackageID('com.woltlab.wcf.user.notification');
+ }
+
+ /**
+ * @see UserNotificationConveyableObjectType::getObjects()
+ */
+ public function getObjects($data) {
+ return array(0 => new VoidUserNotificationConveyableObject());
+ }
+}
+?>
--- /dev/null
+<?php
+namespace wcf\data\user\notification\object\type;
+use wcf\data\DatabaseObject;
+
+/**
+ * Represents a user notification object type.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.object.type
+ * @category Community Framework
+ */
+class UserNotificationObjectType extends DatabaseObject {
+ /**
+ * @see DatabaseObject::$databaseTableName
+ */
+ protected static $databaseTableName = 'user_notification_object_type';
+
+ /**
+ * @see DatabaseObject::$databaseTableIndexName
+ */
+ protected static $databaseTableIndexName = 'objectTypeID';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\object\type;
+use wcf\data\AbstractDatabaseObjectAction;
+
+/**
+ * Executes user notification object type-related actions.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.object.type
+ * @category Community Framework
+ */
+class UserNotificationObjectTypeAction extends AbstractDatabaseObjectAction {
+ /**
+ * @see AbstractDatabaseObjectAction::$className
+ */
+ protected $className = 'wcf\data\user\notification\object\type\UserNotificationObjectTypeEditor';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\object\type;
+use wcf\data\DatabaseObjectEditor;
+
+/**
+ * Provides functions to edit user notification object types.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.object.type
+ * @category Community Framework
+ */
+class UserNotificationObjectTypeEditor extends DatabaseObjectEditor {
+ /**
+ * @see DatabaseObjectEditor::$baseClass
+ */
+ protected static $baseClass = 'wcf\data\user\notification\object\type\UserNotificationObjectType';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\object\type;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of user notification object types.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification
+ * @category Community Framework
+ */
+class UserNotificationObjectTypeList extends DatabaseObjectList {
+ /**
+ * @see DatabaseObjectList::$className
+ */
+ public $className = 'wcf\data\user\notification\object\type\UserNotificationObjectType';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/notification/type/UserNotificationReceivableType.class.php');
+require_once(WCF_DIR.'lib/data/mail/Mail.class.php');
+
+/**
+ * A notification type for sending mail notifications.
+ *
+ * @author Marcel Werk, Oliver Kliebisch
+ * @copyright 2009-2011 WoltLab GmbH, Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.type
+ * @category Community Framework
+ */
+class MailUserNotificationReceivableType implements UserNotificationReceivableType {
+ /**
+ * @see UserNotificationReceivableType::send()
+ */
+ public function send(User $user, UserNotificationConveyableEvent $event, UserNotificationEditor $notification) {
+ // get messages
+ $message = $event->getMessage($this, array(
+ 'user' => $user,
+ 'pageURL' => FileUtil::addTrailingSlash(PAGE_URL)
+ ));
+
+ // append notification mail footer
+ $token = $user->notificationMailToken;
+ if (!$token) {
+ // generate token if not present
+ $token = StringUtil::substring(StringUtil::getHash(serialize(array($user->userID, StringUtil::getRandomID()))), 0, 20);
+ $editor = $user->getEditor();
+ $editor->updateOptions(array('notificationMailToken' => $token));
+ }
+ $message .= '\n'.$event->getLanguage()->getDynamicVariable('wcf.user.notification.type.mail.footer', array(
+ 'user' => $user,
+ 'pageURL' => FileUtil::addTrailingSlash(PAGE_URL),
+ 'token' => $token,
+ 'notification' => $notification
+ ));
+
+ // Use short output as mail subject and strip its HTML
+ $shortMessage = StringUtil::stripHTML($notification->shortOutput);
+
+ // build mail
+ $mail = new Mail(array($user->username => $user->email), $event->getLanguageVariable('wcf.user.notification.type.mail.subject', array('title' => $shortMessage)), $message);
+ $mail->send();
+ }
+
+ /**
+ * @see UserNotificationReceivableType::revoke()
+ */
+ public function send(User $user, UserNotificationConveyableEvent $event, UserNotificationEditor $notification) {
+ // unsupported
+ return;
+ }
+
+ /**
+ * @see UserNotificationReceivableType::getName()
+ */
+ public function getName() {
+ return 'mail';
+ }
+
+ /**
+ * @see UserNotificationReceivableType::getIcon()
+ */
+ public function getIcon() {
+ return 'email';
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/user/User.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/event/UserNotificationConveyableEvent.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/UserNotificationEditor.class.php');
+
+/**
+ * This interface should be implemented by every notification type
+ *
+ * @author Marcel Werk, Oliver Kliebisch
+ * @copyright 2009-2011 WoltLab GmbH, Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.user.notification
+ * @subpackage data.user.notification.type
+ * @category Community Framework
+ */
+interface UserNotificationReceivableType {
+ /**
+ * Sends the notification using this notification transport type
+ *
+ * @param User $user
+ * @param UserNotificationConveyableEvent $event
+ * @param UserNotificationEditor $notification
+ */
+ public function send(User $user, UserNotificationConveyableEvent $event, UserNotificationEditor $notification);
+
+ /**
+ * Tries to revoke the notification. This might not be applicable for
+ * all notification types
+ *
+ * @param User $user
+ * @param UserNotificationConveyableEvent $event
+ * @param UserNotificationEditor $notification
+ */
+ public function revoke(User $user, UserNotificationConveyableEvent $event, UserNotificationEditor $notification);
+
+ /**
+ * Returns the name of the notification type
+ *
+ * @return string
+ */
+ public function getName();
+
+ /**
+ * Returns the icon of the notification type
+ *
+ * @return string
+ */
+ public function getIcon();
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\type;
+use wcf\data\DatabaseObject;
+
+/**
+ * Represents a user notification type.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.type
+ * @category Community Framework
+ */
+class UserNotificationType extends DatabaseObject {
+ /**
+ * @see DatabaseObject::$databaseTableName
+ */
+ protected static $databaseTableName = 'user_notification_type';
+
+ /**
+ * @see DatabaseObject::$databaseTableIndexName
+ */
+ protected static $databaseTableIndexName = 'notificationTypeID';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\type;
+use wcf\data\AbstractDatabaseObjectAction;
+
+/**
+ * Executes user notification type-related actions.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.type
+ * @category Community Framework
+ */
+class UserNotificationTypeAction extends AbstractDatabaseObjectAction {
+ /**
+ * @see AbstractDatabaseObjectAction::$className
+ */
+ protected $className = 'wcf\data\user\notification\type\UserNotificationTypeEditor';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\type;
+use wcf\data\DatabaseObjectEditor;
+
+/**
+ * Provides functions to edit user notification types.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.type
+ * @category Community Framework
+ */
+class UserNotificationTypeEditor extends DatabaseObjectEditor {
+ /**
+ * @see DatabaseObjectEditor::$baseClass
+ */
+ protected static $baseClass = 'wcf\data\user\notification\type\UserNotificationType';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\data\user\notification\type;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of user notification types.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage data.user.notification.type
+ * @category Community Framework
+ */
+class UserNotificationTypeList extends DatabaseObjectList {
+ /**
+ * @see DatabaseObjectList::$className
+ */
+ public $className = 'wcf\data\user\notification\type\UserNotificationType';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/form/AbstractSecureForm.class.php');
+require_once(WCF_DIR.'lib/page/util/menu/UserCPMenu.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationHandler.class.php');
+require_once(WCF_DIR.'lib/data/user/NotificationUser.class.php');
+
+/**
+ * Shows the notification settings form.
+ *
+ * @author Tim Düsterhus, Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage form
+ * @category Community Framework
+ */
+class UserNotificationSettingsForm extends AbstractSecureForm {
+ /**
+ * @see AbstractPage::$templateName
+ */
+ public $templateName = 'userNotificationSettings';
+
+ /**
+ * An array holding all available notification object types
+ *
+ * @var array
+ */
+ public $notificationObjectTypes = array();
+
+ /**
+ * An array holding all available notification types
+ *
+ * @var array
+ */
+ public $notificationTypes = array();
+
+ /**
+ * The activated event notifications in the form
+ *
+ * @var array
+ */
+ public $activeEventNotifications = array();
+
+ /**
+ * The notification user object of the current user
+ *
+ * @var NotificationUser
+ */
+ public $notificationUser = null;
+
+ /**
+ * @see Page::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ $this->notificationUser = new NotificationUser(null, WCF::getUser());
+ $this->notificationObjectTypes = NotificationHandler::getAvailableNotificationObjectTypes();
+ $this->notificationTypes = NotificationHandler::getAvailableNotificationTypes();
+ }
+
+ /**
+ * @see Form::readFormParameters()
+ */
+ public function readFormParameters() {
+ parent::readFormParameters();
+
+ if (isset($_POST['activeEventNotifications']) && is_array($_POST['activeEventNotifications'])) $this->activeEventNotifications = $_POST['activeEventNotifications'];
+ }
+
+ /**
+ * @see Form::validate()
+ */
+ public function validate() {
+ parent::validate();
+
+ // validate checked options and unset wrong settings
+ foreach ($this->activeEventNotifications as $objectType => $events) {
+ if (!isset($this->notificationObjectTypes[$objectType])) {
+ unset ($this->activeEventNotifications[$objectType]);
+ continue;
+ }
+
+ foreach ($events as $eventName => $notificationTypes) {
+ if (!isset($this->notificationObjectTypes[$objectType]['events'][$eventName])) {
+ unset ($this->activeEventNotifications[$objectType][$eventName]);
+ continue;
+ }
+
+ foreach ($notificationTypes as $notificationType => $value) {
+ if (!isset($this->notificationTypes[$notificationType])) {
+ unset ($this->activeEventNotifications[$objectType][$eventName][$notificationType]);
+ continue;
+ }
+ }
+ }
+ }
+
+ $settings = array();
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_user_notification_event_settings
+ WHERE packageID IN (".NotificationHandler::getAvailablePackageIDs().")";
+ $result = WCF::getDB()->sendQuery($sql);
+ while($row = WCF::getDB()->fetchArray($result)) {
+ $settings[$row['objectType']][$row['eventName']][$row['notificationType']] = $row;
+ }
+
+ // add default values
+ foreach ($this->notificationObjectTypes as $name => $objectType) {
+ if (isset($objectType['events'])) {
+ foreach ($objectType['events'] as $eventName => $event) {
+ foreach ($this->notificationTypes as $typeName => $type) {
+ if (!isset($this->activeEventNotifications[$name][$eventName]) || !isset($this->activeEventNotifications[$name][$eventName][$typeName])) {
+ $this->activeEventNotifications[$name][$eventName][$typeName] = 0;
+ }
+ if (isset($settings[$name][$eventName][$typeName]) && !$settings[$name][$eventName][$typeName]['canBeDisabled']) {
+ $this->activeEventNotifications[$name][$eventName][$typeName] = 1;
+ }
+ else if (isset($settings[$name][$eventName][$typeName]) && !$settings[$name][$eventName][$typeName]['enabled']) {
+ $this->activeEventNotifications[$name][$eventName][$typeName] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @see Page::readData()
+ */
+ public function readData() {
+ parent::readData();
+
+ $settings = array();
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_user_notification_event_settings
+ WHERE packageID IN (".NotificationHandler::getAvailablePackageIDs().")";
+ $result = WCF::getDB()->sendQuery($sql);
+ while($row = WCF::getDB()->fetchArray($result)) {
+ $settings[$row['objectType']][$row['eventName']][$row['notificationType']] = $row;
+ }
+
+ if ($this->notificationTypes) {
+ // calculate compatibility map
+ foreach ($this->notificationObjectTypes as $name => $objectType) {
+ if (!isset($objectType['events']) || !is_array($objectType['events'])) {
+ unset ($this->notificationObjectTypes[$name]);
+ continue;
+ }
+ foreach ($objectType['events'] as $eventName => $event) {
+ $this->notificationObjectTypes[$name]['events'][$eventName]->supportedNotificationTypes = array();
+ foreach ($this->notificationTypes as $typeName => $type) {
+ $adminSettings = true;
+ if (isset($settings[$name][$eventName][$typeName]) && !$settings[$name][$eventName][$typeName]['canBeDisabled']) $adminSettings = false;
+ else if (isset($settings[$name][$eventName][$typeName]) && !$settings[$name][$eventName][$typeName]['enabled']) $adminSettings = false;
+ $this->notificationObjectTypes[$name]['events'][$eventName]->supportedNotificationTypes[$typeName] = $event->supportsNotificationType($type) && $adminSettings;
+ }
+ }
+ }
+ }
+
+ if (!count($_POST)) {
+ foreach ($this->notificationObjectTypes as $name => $objectType) {
+ if (isset($objectType['events'])) {
+ foreach ($objectType['events'] as $eventName => $event) {
+ foreach ($this->notificationTypes as $typeName => $type) {
+ if (isset($this->notificationUser->eventNotificationSettings[$name][$eventName][$typeName])) {
+ $this->activeEventNotifications[$name][$eventName][$typeName] = $this->notificationUser->eventNotificationSettings[$name][$eventName][$typeName];
+ }
+ else {
+ if ($typeName == $event->defaultNotificationType) {
+ $this->activeEventNotifications[$name][$eventName][$typeName] = 1;
+ }
+ else {
+ $this->activeEventNotifications[$name][$eventName][$typeName] = 0;
+ }
+ }
+ if (isset($settings[$name][$eventName][$typeName]) && !$settings[$name][$eventName][$typeName]['canBeDisabled']) {
+ $this->activeEventNotifications[$name][$eventName][$typeName] = 1;
+ }
+ else if (isset($settings[$name][$eventName][$typeName]) && !$settings[$name][$eventName][$typeName]['enabled']) {
+ $this->activeEventNotifications[$name][$eventName][$typeName] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @see Page::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'notificationObjectTypes' => $this->notificationObjectTypes,
+ 'notificationTypes' => $this->notificationTypes,
+ 'activeEventNotifications' => $this->activeEventNotifications,
+ 'user' => $this->notificationUser
+ ));
+ }
+
+ /**
+ * @see Page::show()
+ */
+ public function show() {
+ // check module
+ if (!MODULE_USER_NOTIFICATION) {
+ throw new IllegalLinkException();
+ }
+
+ // check permission
+ if (!WCF::getUser()->userID) {
+ throw new PermissionDeniedException();
+ }
+
+ // set active user cp menu item
+ UserCPMenu::getInstance()->setActiveMenuItem('wcf.user.usercp.menu.link.settings.notification');
+
+ // show form
+ parent::show();
+ }
+
+ /**
+ * @see Form::save()
+ */
+ public function save() {
+ parent::save();
+
+ // delete old data but only from this dependency tree
+ $sql = "DELETE FROM wcf".WCF_N."_user_notification_event_to_user
+ WHERE userID = ".WCF::getUser()->userID."
+ AND packageID IN (".NotificationHandler::getAvailablePackageIDs().")";
+ WCF::getDB()->sendQuery($sql);
+
+ $settings = array();
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_user_notification_event_settings
+ WHERE packageID IN (".NotificationHandler::getAvailablePackageIDs().")";
+ $result = WCF::getDB()->sendQuery($sql);
+ while($row = WCF::getDB()->fetchArray($result)) {
+ $settings[$row['objectType']][$row['eventName']][$row['notificationType']] = $row;
+ }
+
+ // prepare new data
+ $inserts = '';
+ foreach ($this->activeEventNotifications as $objectType => $events) {
+ foreach ($events as $eventName => $notificationTypes) {
+ foreach ($notificationTypes as $notificationType => $enabled) {
+ if (isset($settings[$objectType][$eventName][$notificationType]) && !$settings[$objectType][$eventName][$notificationType]['enabled']) {
+ $enabled = false;
+ }
+ else if (isset($settings[$objectType][$eventName][$notificationType]) && !$settings[$objectType][$eventName][$notificationType]['canBeDisabled']) {
+ $enabled = true;
+ }
+
+ $objectTypeObject = NotificationHandler::getNotificationObjectTypeObject($objectType);
+ if (!empty($inserts)) $inserts .= ',';
+ $inserts .= "(".WCF::getUser()->userID.",
+ ".$objectTypeObject->getPackageID().",
+ '".escapeString($objectType)."',
+ '".escapeString($eventName)."',
+ '".escapeString($notificationType)."',
+ ".($enabled ? "1" : "0").")";
+ }
+ }
+
+ }
+
+ if (!empty($inserts)) {
+ $sql = "INSERT INTO wcf".WCF_N."_user_notification_event_to_user
+ (userID, packageID, objectType, eventName, notificationType, enabled)
+ VALUES
+ ".$inserts;
+ WCF::getDB()->sendQuery($sql);
+ }
+
+ $this->saved();
+
+ // show success message
+ WCF::getTPL()->assign('success', true);
+ }
+
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/page/AbstractPage.class.php');
+require_once(WCF_DIR.'lib/data/user/NotificationUser.class.php');
+
+/**
+ * Outputs the number of outstanding notifications
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage page
+ * @category Community Framework
+ */
+class UserNotificationCountPage extends AbstractPage {
+ /**
+ * The notification user object
+ *
+ * @var NotificationUser
+ */
+ public $user = null;
+
+ /**
+ * @see AbstractPage::construct()
+ */
+ public function __construct() {
+ WCF::getSession()->disableUpdate();
+
+ parent::__construct();
+ }
+
+ /**
+ * @see Page::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (!MODULE_USER_NOTIFICATION || !WCF::getUser()->userID) {
+ throw new IllegalLinkException();
+ }
+
+ $this->user = new NotificationUser(null, WCF::getUser(), false);
+ }
+
+ /**
+ * @see Page::show()
+ */
+ public function show() {
+ parent::show();
+
+ HeaderUtil::sendHeaders();
+ echo $this->user->hasOutstandingNotifications();
+ exit;
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/page/AbstractFeedPage.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/FeedNotificationList.class.php');
+
+/**
+ * Prints a list of notification in a rss or atom feed
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage page
+ * @category Community Framework
+ */
+class UserNotificationFeedPage extends AbstractFeedPage {
+ /**
+ * list of notifications
+ *
+ * @var FeedNotificationList
+ */
+ public $notificationList = null;
+
+ /**
+ * @see Page::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ // check user login (only cookie login supported by now)
+ if (WCF::getUser()->userID == 0) {
+ throw new PermissionDeniedException();
+ }
+
+ // get notifications
+ $this->notificationList = new FeedNotificationList();
+ $this->notificationList->sqlConditions .= 'u.userID = '.WCF::getUser()->userID;
+ $this->notificationList->sqlConditions .= ' AND notification.time > '.($this->hours ? (TIME_NOW - $this->hours * 3600) : (TIME_NOW - 30 * 86400));
+ }
+
+ /**
+ * @see Page::readData()
+ */
+ public function readData() {
+ parent::readData();
+
+ $this->notificationList->sqlLimit = $this->limit;
+ $this->notificationList->readObjects();
+ }
+
+ /**
+ * @see Page::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'notifications' => $this->notificationList->getObjects()
+ ));
+ }
+
+ /**
+ * @see Page::show()
+ */
+ public function show() {
+ if (!MODULE_USER_NOTIFICATION) {
+ throw new IllegalLinkException();
+ }
+
+ parent::show();
+
+ // send content
+ WCF::getTPL()->display(($this->format == 'atom' ? 'userNotificationFeedAtom' : 'userNotificationFeedRss2'), false);
+ exit;
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/page/MultipleLinkPage.class.php');
+require_once(WCF_DIR.'lib/page/util/menu/UserCPMenu.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationList.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationEditor.class.php');
+
+/**
+ * Shows the user notification center
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage page
+ * @category Community Framework
+ */
+class UserNotificationPage extends MultipleLinkPage {
+ // system
+ public $templateName = 'userNotification';
+ public $defaultSortField = 'time';
+
+ /**
+ * The list of this users notifications
+ *
+ * @var NotificationList
+ */
+ public $notificationList = null;
+
+ /**
+ * @see Page::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (!MODULE_USER_NOTIFICATION) {
+ throw new IllegalLinkException();
+ }
+
+ $this->notificationList = new NotificationList();
+ $this->notificationList->sqlConditions = "u.userID = ".WCF::getUser()->userID;
+ }
+
+ /**
+ * @see Page::readData()
+ */
+ public function readData() {
+ parent::readData();
+
+ $this->notificationList->sqlSelects = "u.*,";
+ $this->notificationList->sqlLimit = $this->itemsPerPage;
+ $this->notificationList->sqlOffset = $this->itemsPerPage * ($this->pageNo - 1);
+ $this->notificationList->sqlOrderBy = "notification.time DESC";
+ $this->notificationList->readObjects();
+
+ // mark certain notifications as confirmed by now
+ $notificationIDArray = array();
+ foreach($this->notificationList->getObjects() as $notification) {
+ if (!$notification->confirmed && !$notification->event->acceptURL) {
+ $notificationIDArray[] = $notification->notificationID;
+ }
+ }
+
+ if (count($notificationIDArray)) {
+ NotificationEditor::markAllConfirmed($notificationIDArray, array(WCF::getUser()->userID));
+ $user = new NotificationUser(null, WCF::getUser(), false);
+ $user->recalculateOutstandingNotifications();
+ }
+ }
+
+ /**
+ * @see Page::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'notifications' => $this->notificationList->getObjects()
+ ));
+ }
+
+ /**
+ * @see MultipleLinkPage::countItems()
+ */
+ public function countItems() {
+ parent::countItems();
+
+ return $this->notificationList->countObjects();
+ }
+
+ /**
+ * @see Page::show()
+ */
+ public function show() {
+ if (!WCF::getUser()->userID) {
+ throw new PermissionDeniedException();
+ }
+
+ // set active tab
+ UserCPMenu::getInstance()->setActiveMenuItem('wcf.user.usercp.menu.link.management.notification');
+
+ parent::show();
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+require_once(WCF_DIR.'lib/system/cache/CacheBuilder.class.php');
+
+/**
+ * Caches notifications related data
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage system.cache
+ * @category Community Framework
+ */
+class CacheBuilderNotifications implements CacheBuilder {
+ /**
+ * @see CacheBuilder::getData()
+ */
+ public function getData($cacheResource) {
+ list($cache, $packageID) = explode('-', $cacheResource['cache']);
+
+ // initialize arrays
+ $data = array();
+ $data['objectTypes'] = array();
+ $data['events'] = array();
+ $data['notificationTypes'] = array();
+
+ /* object types */
+ // get type ids
+ $typeIDArray = array();
+ $sql = "SELECT objectType, objectTypeID
+ FROM wcf".WCF_N."_user_notification_object_type object_type,
+ wcf".WCF_N."_package_dependency package_dependency
+ WHERE object_type.packageID = package_dependency.dependency
+ AND package_dependency.packageID = ".$packageID."
+ ORDER BY package_dependency.priority";
+ $result = WCF::getDB()->sendQuery($sql);
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $typeIDArray[$row['objectType']] = $row['objectTypeID'];
+ }
+
+ if (count($typeIDArray) > 0) {
+ $sql = "SELECT object_type.*, package.packageDir
+ FROM wcf".WCF_N."_user_notification_object_type object_type
+ LEFT JOIN wcf".WCF_N."_package package
+ ON (package.packageID = object_type.packageID)
+ WHERE object_type.objectTypeID IN (".implode(',', $typeIDArray).")";
+ $result = WCF::getDB()->sendQuery($sql);
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $row['className'] = StringUtil::getClassName($row['classFile']);
+ $data['objectTypes'][] = $row;
+ }
+ }
+
+ /* events */
+ // get event ids
+ $eventIDArray = array();
+ $sql = "SELECT eventName, eventID
+ FROM wcf".WCF_N."_user_notification_event event,
+ wcf".WCF_N."_package_dependency package_dependency
+ WHERE event.packageID = package_dependency.dependency
+ AND package_dependency.packageID = ".$packageID."
+ ORDER BY package_dependency.priority";
+ $result = WCF::getDB()->sendQuery($sql);
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $eventIDArray[$row['eventName']] = $row['eventID'];
+ }
+
+ if (count($eventIDArray) > 0) {
+ $sql = "SELECT event.*, package.packageDir
+ FROM wcf".WCF_N."_user_notification_event event
+ LEFT JOIN wcf".WCF_N."_package package
+ ON (package.packageID = event.packageID)
+ WHERE event.eventID IN (".implode(',', $eventIDArray).")";
+ $result = WCF::getDB()->sendQuery($sql);
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $row['className'] = StringUtil::getClassName($row['classFile']);
+ $data['events'][] = $row;
+ }
+ }
+
+ /* notification types */
+ // get notification type ids
+ $notificationTypeIDArray = array();
+ $sql = "SELECT notificationType, notificationTypeID
+ FROM wcf".WCF_N."_user_notification_type notification_type,
+ wcf".WCF_N."_package_dependency package_dependency
+ WHERE notification_type.packageID = package_dependency.dependency
+ AND package_dependency.packageID = ".$packageID."
+ ORDER BY package_dependency.priority";
+ $result = WCF::getDB()->sendQuery($sql);
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $notificationTypeIDArray[$row['notificationType']] = $row['notificationTypeID'];
+ }
+
+ if (count($notificationTypeIDArray) > 0) {
+ $sql = "SELECT notification_type.*, package.packageDir
+ FROM wcf".WCF_N."_user_notification_type notification_type
+ LEFT JOIN wcf".WCF_N."_package package
+ ON (package.packageID = notification_type.packageID)
+ WHERE notification_type.notificationTypeID IN (".implode(',', $notificationTypeIDArray).")";
+ $result = WCF::getDB()->sendQuery($sql);
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $row['className'] = StringUtil::getClassName($row['classFile']);
+ $data['notificationTypes'][] = $row;
+ }
+ }
+
+ return $data;
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/data/cronjobs/Cronjob.class.php');
+require_once(WCF_DIR.'lib/data/user/NotificationUser.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationEditor.class.php');
+
+/**
+ * Clears outdated notifications
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage system.cronjob
+ * @category Community Framework
+ */
+class CleanUpNotificationsCronjob implements Cronjob {
+ /**
+ * @see Cronjob::execute()
+ */
+ public function execute($data) {
+ if (!MODULE_USER_NOTIFICATION) return;
+
+ if (USER_NOTIFICATION_LIFETIME > -1) {
+ $sql = "SELECT notificationID
+ FROM wcf".WCF_N."_user_notification
+ WHERE confirmationTime < ".(TIME_NOW - 3600 * USER_NOTIFICATION_LIFETIME)."
+ AND confirmationTime <> 0
+ AND confirmed = 1";
+ $result = WCF::getDB()->sendQuery($sql);
+
+ $notificationIDArray = array();
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $notificationIDArray[] = $row['notificationID'];
+ }
+
+ if (count($notificationIDArray)) {
+ NotificationEditor::deleteAll($notificationIDArray);
+ }
+ }
+
+ if (USER_NOTIFICATION_LIFETIME_UNCONFIRMED > 0) {
+ // get affected users
+ $sql = "SELECT user_notification.notificationID, user_notification.userID
+ FROM wcf".WCF_N."_user_notification user_notification
+ WHERE time < ".(TIME_NOW - 3600 * USER_NOTIFICATION_LIFETIME_UNCONFIRMED)."
+ AND confirmed = 0";
+ $result = WCF::getDB()->sendQuery($sql);
+
+ $userIDs = array();
+ $notificationIDArray = array();
+ while ($row = WCF::getDB()->fetchArray($result)) {
+ $notificationIDArray[] = $row['notificationID'];
+ if ($row['userID'] && !isset($userIDs[$row['userID']])) {
+ $userIDs[$row['userID']] = $row['userID'];
+ }
+ }
+
+ if (count($notificationIDArray)) {
+ NotificationEditor::deleteAll($notificationIDArray);
+ }
+
+ // update affected users
+ NotificationUser::recalculateUserNotificationFlags($userIDs);
+ }
+
+ // optimize tables to save some memory (mysql only)
+ if (WCF::getDB()->getDBType() == 'MySQLDatabase' || WCF::getDB()->getDBType() == 'MySQLiDatabase' || WCF::getDB()->getDBType() == 'MySQLPDODatabase') {
+ $sql = "OPTIMIZE TABLE wcf".WCF_N."_user_notification, wcf".WCF_N."_user_notification_message";
+ WCF::getDB()->registerShutdownUpdate($sql);
+ }
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/system/event/EventListener.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationList.class.php');
+require_once(WCF_DIR.'lib/data/user/NotificationUser.class.php');
+
+/**
+ * Shows outstanding user messages notifications
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage system.event.listener
+ * @category Community Framework
+ */
+class StructuredTemplateUserMessagesNotificationListener implements EventListener {
+ /**
+ * @see EventListener::execute()
+ */
+ public function execute($eventObj, $className, $eventName) {
+ // do nothing for guests and spiders or if module is deactivated
+ if (WCF::getUser()->userID == 0 || !MODULE_USER_NOTIFICATION) return;
+
+ $user = new NotificationUser(null, WCF::getUser(), false);
+ if (!$user->hasOutstandingNotifications()) return;
+
+ // get outstanding notifications
+ $notificationList = new NotificationList();
+ $notificationList->sqlSelects .= "notification_message.*,";
+ $notificationList->sqlJoins .= "INNER JOIN wcf".WCF_N."_user_notification_message notification_message
+ ON (notification_message.notificationID = notification.notificationID
+ AND notification_message.notificationType = 'userMessages')";
+ $notificationList->sqlConditions = " u.userID = ".$user->userID."
+ AND u.confirmed = 0";
+ $notificationList->readObjects();
+
+ $notifications = $notificationList->getObjects();
+
+ if (!count($notifications)) return;
+ WCF::getTPL()->assign('notifications', $notifications);
+ WCF::getTPL()->append(array(
+ 'userMessages' => WCF::getTPL()->fetch('userMessagesNotifications')
+ ));
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/system/event/EventListener.class.php');
+require_once(WCF_DIR.'lib/data/user/notification/NotificationList.class.php');
+require_once(WCF_DIR.'lib/data/user/NotificationUser.class.php');
+
+/**
+ * Shows the user panel notification link
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage system.event.listener
+ * @category Community Framework
+ */
+class StructuredTemplateUserPanelNotificationListener implements EventListener {
+ /**
+ * @see EventListener::execute()
+ */
+ public function execute($eventObj, $className, $eventName) {
+ // do nothing for guests and spiders or if module is deactivated
+ if (!USER_NOTIFICATION_USER_MENU_LINK_ACTIVE || WCF::getUser()->userID == 0 || !MODULE_USER_NOTIFICATION) return;
+
+ $user = new NotificationUser(null, WCF::getUser(), false);
+
+ WCF::getTPL()->assign('notificationUser', $user);
+
+ WCF::getTPL()->append(array(
+ 'additionalUserMenuItems' => WCF::getTPL()->fetch('userMenuNotificationLink'),
+ 'additionalHeaderContents' => USER_NOTIFICATION_USER_MENU_LINK_AUTOREFRESH ? WCF::getTPL()->fetch('userMenuPeriodicalExecuter') : ''
+ ));
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\system\package\plugin;
+use wcf\system\cache\CacheHandler;
+use wcf\system\WCF;
+
+/**
+ * This PIP installs, updates or deletes user notification events.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2011 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf.notification
+ * @subpackage system.package.plugin
+ * @category Community Framework
+ */
+class UserNotificationEventPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin {
+ /**
+ * @see AbstractXMLPackageInstallationPlugin::$className
+ */
+ public $className = 'wcf\data\user\notification\event\UserNotificationEventEditor';
+
+ /**
+ * @see AbstractXMLPackageInstallationPlugin::$tableName
+ */
+ public $tableName = 'user_notification_event';
+
+ /**
+ * @see AbstractXMLPackageInstallationPlugin::$tagName
+ */
+ public $tagName = 'event';
+
+ /**
+ * @see AbstractXMLPackageInstallationPlugin::handleDelete()
+ */
+ protected function handleDelete(array $items) {
+ $sql = "DELETE FROM wcf".WCF_N."_".$this->tableName."
+ WHERE packageID = ?
+ AND eventName = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ foreach ($items as $item) {
+ $statement->execute(array(
+ $this->installation->getPackageID(),
+ $item['elements']['name']
+ ));
+ }
+ }
+
+ /**
+ * @see AbstractXMLPackageInstallationPlugin::prepareImport()
+ */
+ protected function prepareImport(array $data) {
+ $objectTypeID = 0;
+ $defaultNotificationTypeID = 0;
+
+ return array(
+ 'eventName' => $data['elements']['name'],
+ 'className' => $data['elements']['classname'],
+ 'objectTypeID' => $objectTypeID,
+ 'defaultNotificationTypeID' => $defaultNotificationTypeID,
+ 'languageCategory' => (isset($data['elements']['languagecategory']) ? $data['elements']['languagecategory'] : ''),
+ 'requiresConfirmation' => (isset($data['elements']['requiresconfirmation']) ? intval($data['elements']['requiresconfirmation']) : 0),
+ 'acceptURL' => (isset($data['elements']['accepturl']) ? $data['elements']['accepturl'] : ''),
+ 'declineURL' => (isset($data['elements']['declineurl']) ? $data['elements']['declineurl'] : ''),
+ 'permissions' => (isset($data['elements']['permissions']) ? $data['elements']['permissions'] : ''),
+ 'options' => (isset($data['elements']['options']) ? $data['elements']['options'] : '')
+ );
+ }
+
+ /**
+ * @see AbstractXMLPackageInstallationPlugin::findExistingItem()
+ */
+ protected function findExistingItem(array $data) {
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_".$this->tableName."
+ WHERE packageID = ?
+ AND eventName = ?";
+ $parameters = array(
+ $this->installation->getPackageID(),
+ $data['eventName']
+ );
+
+ return array(
+ 'sql' => $sql,
+ 'parameters' => $parameters
+ );
+ }
+}
+?>
--- /dev/null
+-- notifications
+DROP TABLE IF EXISTS wcf1_user_notification;
+CREATE TABLE wcf1_user_notification (
+ notificationID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ packageID INT(10) NOT NULL,
+ eventID INT(10) NOT NULL,
+ objectID INT(10) NOT NULL DEFAULT 0,
+ time INT(10) NOT NULL DEFAULT 0,
+ shortOutput VARCHAR(255) DEFAULT NULL,
+ mediumOutput TEXT,
+ longOutput TEXT,
+ additionalData TEXT
+);
+
+-- notification recipients
+DROP TABLE IF EXISTS wcf1_user_notification_to_user;
+CREATE TABLE wcf1_user_notification_to_user (
+ notificationID INT(10) NOT NULL,
+ userID INT(10) NOT NULL,
+ confirmed TINYINT(1) NOT NULL,
+ confirmationTime INT(10) NOT NULL DEFAULT 0,
+ UNIQUE KEY notificationID (notificationID, userID)
+);
+
+-- events that create notifications
+DROP TABLE IF EXISTS wcf1_user_notification_event;
+CREATE TABLE wcf1_user_notification_event (
+ eventID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ packageID INT(10) NOT NULL,
+ eventName VARCHAR(255) NOT NULL DEFAULT '',
+ objectTypeID INT(10) NOT NULL,
+ className VARCHAR(255) NOT NULL DEFAULT '',
+ languageCategory VARCHAR(255) NOT NULL,
+ defaultNotificationTypeID INT(10) NULL,
+ requiresConfirmation TINYINT(1) NOT NULL DEFAULT 0,
+ acceptURL VARCHAR(255) NOT NULL DEFAULT '',
+ declineURL VARCHAR(255) NOT NULL DEFAULT '',
+ permissions TEXT,
+ options TEXT,
+ UNIQUE KEY packageID (packageID, eventName)
+);
+
+-- user configuration for events
+DROP TABLE IF EXISTS wcf1_user_notification_event_to_user;
+CREATE TABLE wcf1_user_notification_event_to_user (
+ userID INT(10) NOT NULL,
+ eventID INT(10) NOT NULL,
+ notificationTypeID INT(10) NOT NULL,
+ enabled TINYINT(1) NOT NULL DEFAULT 0
+);
+
+-- objects that create notifications
+DROP TABLE IF EXISTS wcf1_user_notification_object_type;
+CREATE TABLE wcf1_user_notification_object_type (
+ objectTypeID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ packageID INT(10) NOT NULL,
+ objectType VARCHAR(255) NOT NULL,
+ className VARCHAR(255) NOT NULL,
+ permissions TEXT,
+ options TEXT,
+ UNIQUE KEY packageID (packageID, objectType)
+);
+
+-- notification types (pm, mail, ...)
+DROP TABLE IF EXISTS wcf1_user_notification_type;
+CREATE TABLE wcf1_user_notification_type (
+ notificationTypeID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ packageID INT(10) NOT NULL,
+ notificationType VARCHAR(255) NOT NULL,
+ className VARCHAR(255) NOT NULL,
+ permissions TEXT,
+ options TEXT
+);
+
+ALTER TABLE wcf1_user_notification ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
+ALTER TABLE wcf1_user_notification ADD FOREIGN KEY (eventID) REFERENCES wcf1_user_notification_event (eventID) ON DELETE CASCADE;
+
+ALTER TABLE wcf1_user_notification_to_user ADD FOREIGN KEY (notificationID) REFERENCES wcf1_user_notification (notificationID) ON DELETE CASCADE;
+ALTER TABLE wcf1_user_notification_to_user ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
+
+ALTER TABLE wcf1_user_notification_event ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
+ALTER TABLE wcf1_user_notification_event ADD FOREIGN KEY (objectTypeID) REFERENCES wcf1_user_notification_object_type (objectTypeID) ON DELETE CASCADE;
+ALTER TABLE wcf1_user_notification_event ADD FOREIGN KEY (defaultNotificationTypeID) REFERENCES wcf1_user_notification_type (notificationTypeID) ON DELETE SET NULL;
+
+ALTER TABLE wcf1_user_notification_event_to_user ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
+ALTER TABLE wcf1_user_notification_event_to_user ADD FOREIGN KEY (eventID) REFERENCES wcf1_user_notification_event (eventID) ON DELETE CASCADE;
+ALTER TABLE wcf1_user_notification_event_to_user ADD FOREIGN KEY (notificationTypeID) REFERENCES wcf1_user_notification_type (notificationTypeID) ON DELETE CASCADE;
+
+ALTER TABLE wcf1_user_notification_object_type ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
+
+ALTER TABLE wcf1_user_notification_type ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/language.xsd" languagecode="de-informal">
+ <category name="wcf.user.notification">
+ <item name="wcf.user.notification.title"><![CDATA[Benachrichtigungen]]></item>
+ <item name="wcf.user.notification.stats"><![CDATA[Insgesamt {#$items} Benachrichtigung{if $items != 1}en{/if}]]></item>
+ <item name="wcf.user.notification.noNotifications"><![CDATA[Es liegen momentan keine Benachrichtigungen vor.]]></item>
+ <item name="wcf.user.notification.icon"><![CDATA[Icon]]></item>
+ <item name="wcf.user.notification.text"><![CDATA[Nachricht]]></item>
+ <item name="wcf.user.notification.time"><![CDATA[Zeit]]></item>
+ <item name="wcf.user.notification.confirmAll"><![CDATA[Alle bestätigen]]></item>
+ <item name="wcf.user.notification.settings"><![CDATA[Benachrichtigungseinstellungen]]></item>
+ <item name="wcf.user.notification.settings.saved"><![CDATA[Die Einstellungen wurden erfolgreich gespeichert.]]></item>
+ <item name="wcf.user.notification.location.settings"><![CDATA[Benachrichtigungseinstellungen]]></item>
+ <item name="wcf.user.notification.location.overview"><![CDATA[Benachrichtigungsübersicht]]></item>
+ <item name="wcf.user.notification.type.userMessages"><![CDATA[Infobox]]></item>
+ <item name="wcf.user.notification.type.userMessages.title"><![CDATA[Es liegen folgende neue Benachrichtigungen vor:]]></item>
+ <item name="wcf.user.notification.type.mail"><![CDATA[E-Mail]]></item>
+ <item name="wcf.user.notification.type.mail.subject"><![CDATA[{@$title}]]></item>
+ <item name="wcf.user.notification.type.mail.footer"><![CDATA[
+
+Du kannst die Einstellungen für Deine Benachrichtigungen auf {lang}{@PAGE_TITLE}{/lang} unter folgender URL detailliert konfigurieren:
+{@$pageURL}index.php?form=UserNotificationSettings
+Möchtest Du in Zukunft diese Benachrichtigung per Mail nicht mehr erhalten, rufen diesen Link auf, um diese zu deaktivieren: {@$pageURL}index.php?action=NotificationDisable¬ificationID={@$notification->notificationID}&userID={@$user->userID}&token={@$token}
+
+]]></item>
+ <item name="wcf.user.notification.type.mail.disabled"><![CDATA[Du hast die Benachrichtung für dieses Ereignis per E-Mail deaktiviert. Du kannst die Benachrichtigung in Deinen Profileinstellungen jederzeit erneut aktivieren.]]></item>
+ <item name="wcf.user.notification.feed"><![CDATA[Neuste Benachrichtigungen]]></item>
+ <item name="wcf.user.notification.feed.title"><![CDATA[Benachrichtigungen abonnieren]]></item>
+ <item name="wcf.user.notification.feed.description"><![CDATA[Die neusten Benachrichtigungen von "{lang}{PAGE_TITLE}{/lang}"]]></item>
+ <item name="wcf.user.notification.error.alreadyAccepted"><![CDATA[Du hast diese Benachrichtigung bereits bestätigt.]]></item>
+ <item name="wcf.user.notification.object.type.void"><![CDATA[Allgemein]]></item>
+ </category>
+ <category name="wcf.user.usercp">
+ <item name="wcf.user.usercp.menu.link.settings.notification"><![CDATA[Benachrichtigungen]]></item>
+ <item name="wcf.user.usercp.menu.link.management.notification"><![CDATA[Benachrichtigungen]]></item>
+ </category>
+ <category name="wcf.header.userMenu">
+ <item name="wcf.header.userMenu.userNotifications"><![CDATA[Benachrichtigungen]]></item>
+ </category>
+ <category name="wcf.acp.option">
+ <item name="wcf.acp.option.module_user_notification"><![CDATA[Benachrichtigungen]]></item>
+ <item name="wcf.acp.option.module_user_notification.description"><![CDATA[Aktiviert das Benutzerbenachrichtigungssystem.]]></item>
+ <item name="wcf.acp.option.category.user.notification"><![CDATA[Benachrichtigungen]]></item>
+ <item name="wcf.acp.option.category.user.notification.description"><![CDATA[]]></item>
+ <item name="wcf.acp.option.category.user.notification.general"><![CDATA[Allgemein]]></item>
+ <item name="wcf.acp.option.category.user.notification.general.description"><![CDATA[]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_active"><![CDATA[Link im Benutzermenü anzeigen]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_active.description"><![CDATA[Ist diese Option aktiviert, wird ein Link zur Nachrichtenübersicht im Seitenkopf angezeigt.]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh"><![CDATA[Link im Benutzermenü automatisch aktualisieren]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh.description"><![CDATA[Ist diese Option aktiviert, aktualisiert sich die Anzeige der Nachrichtenübersicht im Seitenkopf regelmäßig mittels AJAX. Die Aktivierung dieser Funktion verursacht eine höhere Serverlast.]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh_intervall"><![CDATA[Aktualisierungsintervall [Sekunden]]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh_intervall.description"><![CDATA[Wie häufig soll sich der Link zur Nachrichtenübersicht aktualisieren?]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime"><![CDATA[Lebenspanne bestätigter Benachrichtigungen [Stunden]]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime.description"><![CDATA[Gib an, wie lange eine Benachrichtigung nach Bestätigung aufbewahrt werden sollen. -1 deaktiviert die automatische Löschung von Benachrichtigungen.]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime_unconfirmed"><![CDATA[Lebenspanne unbestätigter Benachrichtigungen [Stunden]]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime_unconfirmed.description"><![CDATA[Gib an, wie lange eine Benachrichtigung aufbewahrt werden soll, bevor sie auch <strong>ohne Bestätigung</strong> gelöscht wird. 0 deaktiviert die automatische Löschung unbestätigter Benachrichtigungen.]]></item>
+ </category>
+ <category name="wcf.acp.package">
+ <item name="wcf.acp.package.step.install.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Benachrichtigungsobjekte werden installiert ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Benachrichtigungsobjekte werden deinstalliert ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Benachrichtigungsobjekte werden aktualisiert ...]]></item>
+ <item name="wcf.acp.package.step.install.NotificationTypePackageInstallationPlugin"><![CDATA[Benachrichtigungstypen werden installiert ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationTypePackageInstallationPlugin"><![CDATA[Benachrichtigungstypen werden deinstalliert ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationTypePackageInstallationPlugin"><![CDATA[Benachrichtigungstypen werden aktualisiert ...]]></item>
+ <item name="wcf.acp.package.step.install.NotificationEventPackageInstallationPlugin"><![CDATA[Benachrichtigungsereignisse werden installiert ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationEventPackageInstallationPlugin"><![CDATA[Benachrichtigungsereignisse werden deinstalliert ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationEventPackageInstallationPlugin"><![CDATA[Benachrichtigungsereignisse werden aktualisiert ...]]></item>
+ </category>
+</language>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/language.xsd" languagecode="de">
+ <category name="wcf.user.notification">
+ <item name="wcf.user.notification.title"><![CDATA[Benachrichtigungen]]></item>
+ <item name="wcf.user.notification.stats"><![CDATA[Insgesamt {#$items} Benachrichtigung{if $items != 1}en{/if}]]></item>
+ <item name="wcf.user.notification.noNotifications"><![CDATA[Es liegen momentan keine Benachrichtigungen vor.]]></item>
+ <item name="wcf.user.notification.icon"><![CDATA[Icon]]></item>
+ <item name="wcf.user.notification.text"><![CDATA[Nachricht]]></item>
+ <item name="wcf.user.notification.time"><![CDATA[Zeit]]></item>
+ <item name="wcf.user.notification.confirmAll"><![CDATA[Alle bestätigen]]></item>
+ <item name="wcf.user.notification.settings"><![CDATA[Benachrichtigungseinstellungen]]></item>
+ <item name="wcf.user.notification.settings.saved"><![CDATA[Die Einstellungen wurden erfolgreich gespeichert.]]></item>
+ <item name="wcf.user.notification.location.settings"><![CDATA[Benachrichtigungseinstellungen]]></item>
+ <item name="wcf.user.notification.location.overview"><![CDATA[Benachrichtigungsübersicht]]></item>
+ <item name="wcf.user.notification.type.userMessages"><![CDATA[Infobox]]></item>
+ <item name="wcf.user.notification.type.userMessages.title"><![CDATA[Es liegen folgende neue Benachrichtigungen vor:]]></item>
+ <item name="wcf.user.notification.type.mail"><![CDATA[E-Mail]]></item>
+ <item name="wcf.user.notification.type.mail.subject"><![CDATA[{@$title}]]></item>
+ <item name="wcf.user.notification.type.mail.footer"><![CDATA[
+
+Sie können die Einstellungen für Ihre Benachrichtigungen auf {lang}{@PAGE_TITLE}{/lang} unter folgender URL detailliert konfigurieren:
+{@$pageURL}index.php?form=UserNotificationSettings
+Möchten Sie in Zukunft diese Benachrichtigung per Mail nicht mehr erhalten, rufen Sie diesen Link auf, um diese zu deaktivieren: {@$pageURL}index.php?action=NotificationDisable¬ificationID={@$notification->notificationID}&userID={@$user->userID}&token={@$token}
+
+]]></item>
+ <item name="wcf.user.notification.type.mail.disabled"><![CDATA[Sie haben die Benachrichtung für dieses Ereignis per E-Mail deaktiviert. Sie können die Benachrichtigung in Ihren Profileinstellungen jederzeit erneut aktivieren.]]></item>
+ <item name="wcf.user.notification.feed"><![CDATA[Neuste Benachrichtigungen]]></item>
+ <item name="wcf.user.notification.feed.title"><![CDATA[Benachrichtigungen abonnieren]]></item>
+ <item name="wcf.user.notification.feed.description"><![CDATA[Die neusten Benachrichtigungen von "{lang}{PAGE_TITLE}{/lang}"]]></item>
+ <item name="wcf.user.notification.error.alreadyAccepted"><![CDATA[Sie haben diese Benachrichtigung bereits bestätigt.]]></item>
+ <item name="wcf.user.notification.object.type.void"><![CDATA[Allgemein]]></item>
+ </category>
+ <category name="wcf.user.usercp">
+ <item name="wcf.user.usercp.menu.link.settings.notification"><![CDATA[Benachrichtigungen]]></item>
+ <item name="wcf.user.usercp.menu.link.management.notification"><![CDATA[Benachrichtigungen]]></item>
+ </category>
+ <category name="wcf.header.userMenu">
+ <item name="wcf.header.userMenu.userNotifications"><![CDATA[Benachrichtigungen]]></item>
+ </category>
+ <category name="wcf.acp.option">
+ <item name="wcf.acp.option.module_user_notification"><![CDATA[Benachrichtigungen]]></item>
+ <item name="wcf.acp.option.module_user_notification.description"><![CDATA[Aktiviert das Benutzerbenachrichtigungssystem.]]></item>
+ <item name="wcf.acp.option.category.user.notification"><![CDATA[Benachrichtigungen]]></item>
+ <item name="wcf.acp.option.category.user.notification.description"><![CDATA[]]></item>
+ <item name="wcf.acp.option.category.user.notification.general"><![CDATA[Allgemein]]></item>
+ <item name="wcf.acp.option.category.user.notification.general.description"><![CDATA[]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_active"><![CDATA[Link im Benutzermenü anzeigen]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_active.description"><![CDATA[Ist diese Option aktiviert, wird ein Link zur Nachrichtenübersicht im Seitenkopf angezeigt.]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh"><![CDATA[Link im Benutzermenü automatisch aktualisieren]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh.description"><![CDATA[Ist diese Option aktiviert, aktualisiert sich die Anzeige der Nachrichtenübersicht im Seitenkopf regelmäßig mittels AJAX. Die Aktivierung dieser Funktion verursacht eine höhere Serverlast.]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh_intervall"><![CDATA[Aktualisierungsintervall [Sekunden]]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh_intervall.description"><![CDATA[Wie häufig soll sich der Link zur Nachrichtenübersicht aktualisieren?]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime"><![CDATA[Lebenspanne bestätigter Benachrichtigungen [Stunden]]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime.description"><![CDATA[Geben Sie an, wie lange eine Benachrichtigung nach Bestätigung aufbewahrt werden sollen. -1 deaktiviert die automatische Löschung von Benachrichtigungen.]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime_unconfirmed"><![CDATA[Lebenspanne unbestätigter Benachrichtigungen [Stunden]]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime_unconfirmed.description"><![CDATA[Geben Sie an, wie lange eine Benachrichtigung aufbewahrt werden soll, bevor sie auch <strong>ohne Bestätigung</strong> gelöscht wird. 0 deaktiviert die automatische Löschung unbestätigter Benachrichtigungen.]]></item>
+ </category>
+ <category name="wcf.acp.package">
+ <item name="wcf.acp.package.step.install.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Benachrichtigungsobjekte werden installiert ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Benachrichtigungsobjekte werden deinstalliert ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Benachrichtigungsobjekte werden aktualisiert ...]]></item>
+ <item name="wcf.acp.package.step.install.NotificationTypePackageInstallationPlugin"><![CDATA[Benachrichtigungstypen werden installiert ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationTypePackageInstallationPlugin"><![CDATA[Benachrichtigungstypen werden deinstalliert ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationTypePackageInstallationPlugin"><![CDATA[Benachrichtigungstypen werden aktualisiert ...]]></item>
+ <item name="wcf.acp.package.step.install.NotificationEventPackageInstallationPlugin"><![CDATA[Benachrichtigungsereignisse werden installiert ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationEventPackageInstallationPlugin"><![CDATA[Benachrichtigungsereignisse werden deinstalliert ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationEventPackageInstallationPlugin"><![CDATA[Benachrichtigungsereignisse werden aktualisiert ...]]></item>
+ </category>
+</language>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/language.xsd" languagecode="en">
+ <category name="wcf.user.notification">
+ <item name="wcf.user.notification.title"><![CDATA[Notifications]]></item>
+ <item name="wcf.user.notification.stats"><![CDATA[Overall {#$items} notification{if $items != 1}s{/if}]]></item>
+ <item name="wcf.user.notification.noNotifications"><![CDATA[There are no notifications at the moment.]]></item>
+ <item name="wcf.user.notification.icon"><![CDATA[Icon]]></item>
+ <item name="wcf.user.notification.text"><![CDATA[Message]]></item>
+ <item name="wcf.user.notification.time"><![CDATA[Time]]></item>
+ <item name="wcf.user.notification.confirmAll"><![CDATA[Confirm all]]></item>
+ <item name="wcf.user.notification.settings"><![CDATA[Notification settings]]></item>
+ <item name="wcf.user.notification.settings.saved"><![CDATA[The settings were successfully saved.]]></item>
+ <item name="wcf.user.notification.location.settings"><![CDATA[Notification settings]]></item>
+ <item name="wcf.user.notification.location.overview"><![CDATA[Notification overview]]></item>
+ <item name="wcf.user.notification.type.userMessages"><![CDATA[Infobox]]></item>
+ <item name="wcf.user.notification.type.userMessages.title"><![CDATA[You have the following new notifications:]]></item>
+ <item name="wcf.user.notification.type.mail"><![CDATA[E-Mail]]></item>
+ <item name="wcf.user.notification.type.mail.subject"><![CDATA[{@$title}]]></item>
+ <item name="wcf.user.notification.type.mail.footer"><![CDATA[
+
+
+You can change your personal notification settings on {lang}{@PAGE_TITLE}{/lang} under the following URL:
+{@$pageURL}index.php?form=UserNotificationSettings
+If you do not want to recevive this mail notification in future just follow this link: {@$pageURL}index.php?action=NotificationDisable¬ificationID={@$notification->notificationID}&userID={@$user->userID}&token={@$token}
+
+]]></item>
+ <item name="wcf.user.notification.type.mail.disabled"><![CDATA[You have disabled the mail notification successfully. You can reactive this notification in your profile settings at any time.]]></item>
+ <item name="wcf.user.notification.feed"><![CDATA[Newest notifications]]></item>
+ <item name="wcf.user.notification.feed.title"><![CDATA[Subcribe to notifications]]></item>
+ <item name="wcf.user.notification.feed.description"><![CDATA[Your newest notifications on "{lang}{PAGE_TITLE}{/lang}"]]></item>
+ <item name="wcf.user.notification.error.alreadyAccepted"><![CDATA[You have already confirmed this notification.]]></item>
+ <item name="wcf.user.notification.object.type.void"><![CDATA[General]]></item>
+ </category>
+ <category name="wcf.user.usercp">
+ <item name="wcf.user.usercp.menu.link.settings.notification"><![CDATA[Notifications]]></item>
+ <item name="wcf.user.usercp.menu.link.management.notification"><![CDATA[Notifications]]></item>
+ </category>
+ <category name="wcf.header.userMenu">
+ <item name="wcf.header.userMenu.userNotifications"><![CDATA[Notifications]]></item>
+ </category>
+ <category name="wcf.acp.option">
+ <item name="wcf.acp.option.module_user_notification"><![CDATA[Notifications]]></item>
+ <item name="wcf.acp.option.module_user_notification.description"><![CDATA[Activates the user notification system.]]></item>
+ <item name="wcf.acp.option.category.user.notification"><![CDATA[Notifications]]></item>
+ <item name="wcf.acp.option.category.user.notification.description"><![CDATA[]]></item>
+ <item name="wcf.acp.option.category.user.notification.general"><![CDATA[General]]></item>
+ <item name="wcf.acp.option.category.user.notification.general.description"><![CDATA[]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_active"><![CDATA[Show user menu link]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_active.description"><![CDATA[If this option is activated, a link to the user notification overview will be displayed in each user's user panel.]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh"><![CDATA[Automatic user menu link refresh]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh.description"><![CDATA[If this option is activated, the user menu link will refresh itself automatically using AJAX. This feature increases the server load.]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh_intervall"><![CDATA[Refresh intervall [Seconds]]]></item>
+ <item name="wcf.acp.option.user_notification_user_menu_link_autorefresh_intervall.description"><![CDATA[How often shall the link refresh itself?]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime"><![CDATA[Lifetime of confirmed notifications [Hours]]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime.description"><![CDATA[Enter for how many hours confirmed notifications should be kept before deletion. -1 deactivates the automatic deletion of old confirmed notifications.]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime_unconfirmed"><![CDATA[Lifetime of unconfirmed notifications [Hours]]]></item>
+ <item name="wcf.acp.option.user_notification_lifetime_unconfirmed.description"><![CDATA[Enter for how many hours unconfirmed notifications should be kept before deletion. 0 deactivates the automatic deletion of notifications.]]></item>
+ </category>
+ <category name="wcf.acp.package">
+ <item name="wcf.acp.package.step.install.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Installing notification objects ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Uninstalling notification objects ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationObjectTypePackageInstallationPlugin"><![CDATA[Updating notification objects ...]]></item>
+ <item name="wcf.acp.package.step.install.NotificationTypePackageInstallationPlugin"><![CDATA[Installing notification types ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationTypePackageInstallationPlugin"><![CDATA[Uninstalling notification types ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationTypePackageInstallationPlugin"><![CDATA[Updating notification types ...]]></item>
+ <item name="wcf.acp.package.step.install.NotificationEventPackageInstallationPlugin"><![CDATA[Installing notification events ...]]></item>
+ <item name="wcf.acp.package.step.uninstall.NotificationEventPackageInstallationPlugin"><![CDATA[Uninstalling notification events ...]]></item>
+ <item name="wcf.acp.package.step.update.NotificationEventPackageInstallationPlugin"><![CDATA[Updating notification events ...]]></item>
+ </category>
+</language>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/notification-object-type.xsd">
+ <import>
+ <type>
+ <name>void</name>
+ <classfile>lib/data/user/notification/object/VoidNotificationObjectType.class.php</classfile>
+ </type>
+ </import>
+</data>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/notification-type.xsd">
+ <import>
+ <type>
+ <name>mail</name>
+ <classfile>lib/data/user/notification/type/MailUserNotificationReceivableType.class.php</classfile>
+ </type>
+ </import>
+</data>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/options.xsd">
+ <import>
+ <categories>
+ <category name="user.notification">
+ <parent>user</parent>
+ <options>module_user_notification</options>
+ </category>
+ <category name="user.notification.general">
+ <parent>user.notification</parent>
+ <showorder>1</showorder>
+ <options>module_user_notification</options>
+ </category>
+ </categories>
+ <options>
+ <option name="module_user_notification">
+ <categoryname>module.user</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>1</defaultvalue>
+ </option>
+ <option name="user_notification_user_menu_link_active">
+ <categoryname>user.notification.general</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>1</defaultvalue>
+ <enableoptions>user_notification_user_menu_link_autorefresh</enableoptions>
+ </option>
+ <option name="user_notification_user_menu_link_autorefresh">
+ <categoryname>user.notification.general</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <enableoptions>user_notification_user_menu_link_autorefresh_intervall</enableoptions>
+ </option>
+ <option name="user_notification_user_menu_link_autorefresh_intervall">
+ <categoryname>user.notification.general</categoryname>
+ <optiontype>integer</optiontype>
+ <defaultvalue>30</defaultvalue>
+ </option>
+ <option name="user_notification_lifetime">
+ <categoryname>user.notification.general</categoryname>
+ <optiontype>integer</optiontype>
+ <defaultvalue>48</defaultvalue>
+ </option>
+ <option name="user_notification_lifetime_unconfirmed">
+ <categoryname>user.notification.general</categoryname>
+ <optiontype>integer</optiontype>
+ <defaultvalue>0</defaultvalue>
+ </option>
+ </options>
+ </import>
+</data>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package name="com.woltlab.wcf.user.notification" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/package.xsd">
+ <packageinformation>
+ <packagename>User Notification System</packagename>
+ <version>1.0.0 Alpha 1</version>
+ <date>2010-08-22</date>
+ <isunique>1</isunique>
+ </packageinformation>
+
+ <authorinformation>
+ <author>WoltLab GmbH, Oliver Kliebisch and Tim Düsterhus</author>
+ <authorurl>http://www.woltlab.com</authorurl>
+ </authorinformation>
+
+ <requiredpackages>
+ <requiredpackage minversion="2.0.0 Alpha 1">com.woltlab.wcf</requiredpackage>
+ </requiredpackages>
+
+ <instructions type="install">
+ <instruction type="packageinstallationplugins">pip.xml</instruction>
+ <instruction type="files">files.tar</instruction>
+ <instruction type="sql">install.sql</instruction>
+ </instructions>
+</package>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/page-location.xsd">
+ <import>
+ <pagelocation name="wcf.user.notification.location.settings">
+ <pattern><![CDATA[index\.php\?form=UserNotificationSettings]]></pattern>
+ <options>module_user_notification</options>
+ </pagelocation>
+ <pagelocation name="wcf.user.notification.location.overview">
+ <pattern><![CDATA[index\.php\?page=UserNotification$]]></pattern>
+ <options>module_user_notification</options>
+ </pagelocation>
+ </import>
+</data>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/pip.xsd">
+ <import>
+ <pip name="userNotificationEvent">wcf\system\package\plugin\UserNotificationEventPackageInstallationPlugin</pip>
+ <pip name="userNotificationObjectType">wcf\system\package\plugin\UserNotificationObjectTypePackageInstallationPlugin</pip>
+ <pip name="userNotificationType">wcf\system\package\plugin\UserNotificationTypePackageInstallationPlugin</pip>
+ </import>
+</data>
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/acp/package/plugin/AbstractXMLPackageInstallationPlugin.class.php');
+
+/**
+ * Install, updates and uninstalls notification events
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage acp.package.plugin
+ * @category Community Framework
+ */
+class NotificationEventPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin {
+ public $tagName = 'notificationevent';
+ public $tableName = 'user_notification_event';
+
+ /**
+ * @see PackageInstallationPlugin::install()
+ */
+ public function install() {
+ parent::install();
+
+ if (!$xml = $this->getXML()) {
+ return;
+ }
+
+ // Create an array with the data blocks (import or delete) from the xml file.
+ $notificationEventXML = $xml->getElementTree('data');
+
+ // Loop through the array and install or uninstall items.
+ foreach ($notificationEventXML['children'] as $key => $block) {
+ if (count($block['children'])) {
+ // Handle the import instructions
+ if ($block['name'] == 'import') {
+ // Loop through items and create or update them.
+ foreach ($block['children'] as $notificationEvent) {
+ // Extract item properties.
+ foreach ($notificationEvent['children'] as $child) {
+ if (!isset($child['cdata'])) continue;
+ $notificationEvent[$child['name']] = $child['cdata'];
+ }
+
+ // default values
+ $name = $objectType = $classFile = $languageCategory = $defaultNotificationType = $icon = $acceptURL = $declineURL = $permissions = $options = '';
+ $requiresConfirmation = 0;
+
+ // get values
+ if (isset($notificationEvent['name'])) $name = $notificationEvent['name'];
+ if (isset($notificationEvent['objecttype'])) $objectType = $notificationEvent['objecttype'];
+ if (isset($notificationEvent['classfile'])) $classFile = $notificationEvent['classfile'];
+ if (isset($notificationEvent['languagecategory'])) $languageCategory = $notificationEvent['languagecategory'];
+ if (isset($notificationEvent['defaultnotificationtype'])) $defaultNotificationType = $notificationEvent['defaultnotificationtype'];
+ if (isset($notificationEvent['icon'])) $icon = $notificationEvent['icon'];
+ if (isset($notificationEvent['requiresconfirmation'])) $requiresConfirmation = $notificationEvent['requiresconfirmation'] ? 1 : 0;
+ if (isset($notificationEvent['accepturl'])) $acceptURL = $notificationEvent['accepturl'];
+ if (isset($notificationEvent['declineurl'])) $declineURL = $notificationEvent['declineurl'];
+ if (isset($notificationEvent['permissions'])) $permissions = $notificationEvent['permissions'];
+ if (isset($notificationEvent['options'])) $options = $notificationEvent['options'];
+
+ // insert items
+ $sql = "INSERT INTO wcf".WCF_N."_".$this->tableName."
+ (packageID, eventName, objectType, classFile, languageCategory, defaultNotificationType, icon, requiresConfirmation, acceptURL, declineURL, permissions, options)
+ VALUES (".$this->installation->getPackageID().",
+ '".escapeString($name)."',
+ '".escapeString($objectType)."',
+ '".escapeString($classFile)."',
+ '".escapeString($languageCategory)."',
+ '".escapeString($defaultNotificationType)."',
+ '".escapeString($icon)."',
+ '".escapeString($requiresConfirmation)."',
+ '".escapeString($acceptURL)."',
+ '".escapeString($declineURL)."',
+ '".escapeString($permissions)."',
+ '".escapeString($options)."')
+ ON DUPLICATE KEY UPDATE objectType = VALUES(objectType),
+ classFile = VALUES(classFile),
+ languageCategory = VALUES(languageCategory),
+ defaultNotificationType = VALUES(defaultNotificationType),
+ icon = VALUES(icon),
+ requiresConfirmation = VALUES(requiresConfirmation),
+ acceptURL = VALUES(acceptURL),
+ declineURL = VALUES(declineURL),
+ permissions = VALUES(permissions),
+ options = VALUES(options)";
+ WCF::getDB()->sendQuery($sql);
+ }
+ }
+ // Handle the delete instructions.
+ else if ($block['name'] == 'delete' && $this->installation->getAction() == 'update') {
+ // Loop through items and delete them.
+ $nameArray = array();
+ foreach ($block['children'] as $notificationEvent) {
+ // Extract item properties.
+ foreach ($notificationEvent['children'] as $child) {
+ if (!isset($child['cdata'])) continue;
+ $notificationEvent[$child['name']] = $child['cdata'];
+ }
+
+ if (empty($notificationEvent['name'])) {
+ throw new SystemException("Required 'name' attribute for notification event is missing", 13023);
+ }
+ $nameArray[] = $notificationEvent['name'];
+ }
+ if (count($nameArray)) {
+ $sql = "DELETE FROM wcf".WCF_N."_".$this->tableName."
+ WHERE packageID = ".$this->installation->getPackageID()."
+ AND eventName IN ('".implode("','", array_map('escapeString', $nameArray))."')";
+ WCF::getDB()->sendQuery($sql);
+ }
+ }
+ }
+ }
+ }
+
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/acp/package/plugin/NotificationTypePackageInstallationPlugin.class.php');
+
+/**
+ * Install, updates and uninstalls notification object types
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage acp.package.plugin
+ * @category Community Framework
+ */
+class NotificationObjectTypePackageInstallationPlugin extends NotificationTypePackageInstallationPlugin {
+ public $tagName = 'notificationobjecttype';
+ public $tableName = 'user_notification_object_type';
+ public $fieldName = 'objectType';
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// wcf imports
+require_once(WCF_DIR.'lib/acp/package/plugin/AbstractXMLPackageInstallationPlugin.class.php');
+
+/**
+ * Install, updates and uninstalls notification types
+ *
+ * @author Oliver Kliebisch
+ * @copyright 2009-2010 Oliver Kliebisch
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.community.wcf.user.notification
+ * @subpackage acp.package.plugin
+ * @category Community Framework
+ */
+class NotificationTypePackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin {
+ public $tagName = 'notificationtype';
+ public $tableName = 'user_notification_type';
+ public $fieldName = 'notificationType';
+
+ /**
+ * @see PackageInstallationPlugin::install()
+ */
+ public function install() {
+ parent::install();
+
+ if (!$xml = $this->getXML()) {
+ return;
+ }
+
+ // Create an array with the data blocks (import or delete) from the xml file.
+ $notificationTypeXML = $xml->getElementTree('data');
+
+ // Loop through the array and install or uninstall items.
+ foreach ($notificationTypeXML['children'] as $key => $block) {
+ if (count($block['children'])) {
+ // Handle the import instructions
+ if ($block['name'] == 'import') {
+ // Loop through items and create or update them.
+ foreach ($block['children'] as $notificationType) {
+ // Extract item properties.
+ foreach ($notificationType['children'] as $child) {
+ if (!isset($child['cdata'])) continue;
+ $notificationType[$child['name']] = $child['cdata'];
+ }
+
+ // default values
+ $name = $classFile = $permissions = $options = '';
+
+ // get values
+ if (isset($notificationType['name'])) $name = $notificationType['name'];
+ if (isset($notificationType['classfile'])) $classFile = $notificationType['classfile'];
+ if (isset($notificationType['permissions'])) $permissions = $notificationType['permissions'];
+ if (isset($notificationType['options'])) $options = $notificationType['options'];
+
+ // insert items
+ $sql = "INSERT INTO wcf".WCF_N."_".$this->tableName."
+ (packageID, ".$this->fieldName.", classFile, permissions, options)
+ VALUES (".$this->installation->getPackageID().",
+ '".escapeString($name)."',
+ '".escapeString($classFile)."',
+ '".escapeString($permissions)."',
+ '".escapeString($options)."')
+ ON DUPLICATE KEY UPDATE classFile = VALUES(classFile),
+ permissions = VALUES(permissions),
+ options = VALUES(options)";
+ WCF::getDB()->sendQuery($sql);
+ }
+ }
+ // Handle the delete instructions.
+ else if ($block['name'] == 'delete' && $this->installation->getAction() == 'update') {
+ // Loop through items and delete them.
+ $nameArray = array();
+ foreach ($block['children'] as $notificationType) {
+ // Extract item properties.
+ foreach ($notificationType['children'] as $child) {
+ if (!isset($child['cdata'])) continue;
+ $notificationType[$child['name']] = $child['cdata'];
+ }
+
+ if (empty($notificationType['name'])) {
+ throw new SystemException("Required 'name' attribute for ".$this->fieldName." is missing", 13023);
+ }
+ $nameArray[] = $notificationType['name'];
+ }
+ if (count($nameArray)) {
+ $sql = "DELETE FROM wcf".WCF_N."_".$this->tableName."
+ WHERE packageID = ".$this->installation->getPackageID()."
+ AND ".$this->fieldName." IN ('".implode("','", array_map('escapeString', $nameArray))."')";
+ WCF::getDB()->sendQuery($sql);
+ }
+ }
+ }
+ }
+ }
+}
+?>
\ No newline at end of file
--- /dev/null
+<li id="userMenuNotificationOverview"{if $notificationUser->hasOutstandingNotifications()} class="new"{/if}><a href="index.php?page=UserNotification{@SID_ARG_2ND}"><img src="{icon}infoS.png{/icon}" alt="" /> <span>{lang}wcf.header.userMenu.userNotifications{/lang}{if $notificationUser->hasOutstandingNotifications()} ({#$notificationUser->hasOutstandingNotifications()}){/if}</span></a></li>
\ No newline at end of file
--- /dev/null
+<script type="text/javascript">
+//<![CDATA[
+ new PeriodicalExecuter(function() {
+ new Ajax.Request('index.php?page=UserNotificationCount'+SID_ARG_2ND, {
+ method: 'get',
+ onSuccess: function(transport) {
+ outstandingNotifications = parseInt(transport.responseText);
+ if (outstandingNotifications > 0) {
+ $('userMenuNotificationOverview').addClassName('new');
+ $('userMenuNotificationOverview').down('span').update('{lang}wcf.header.userMenu.userNotifications{/lang} (' + outstandingNotifications + ')');
+ new Effect.Pulsate('userMenuNotificationOverview', { pulses: 2, duration: 3.0 });
+ }
+ }
+ });
+ }, {USER_NOTIFICATION_USER_MENU_LINK_AUTOREFRESH_INTERVALL});
+//]]>
+</script>
\ No newline at end of file
--- /dev/null
+ <div class="info deletable" id="outstandingNotificationsContainer">
+ <a href="index.php?action=NotificationConfirm{if $this->session->requestMethod == 'GET'}&url={$this->session->requestURI|rawurlencode}{/if}&t={@SECURITY_TOKEN}{@SID_ARG_2ND}" class="close deleteButton"><img src="{icon}closeS.png{/icon}" alt="" title="{lang}wcf.user.notification.confirmAll{/lang}" longdesc="" /></a>
+ <p>{lang}wcf.user.notification.type.userMessages.title{/lang}</p>
+ <ul class="itemList">
+ {foreach from=$notifications item=notification}
+ {assign var=languageCategory value=$notification->event->languageCategory}
+ {assign var=eventName value=$notification->eventName}
+ <li class="deletable"{if $notification->event->icon} style="list-style-image:url('{icon}{$notification->event->icon}S.png{/icon}');"{/if}>
+ {if $notification->event->requiresConfirmation}
+ {assign var=acceptURL value=$notification->event->getAcceptURL($notification)}
+ {assign var=declineURL value=$notification->event->getDeclineURL($notification)}
+ <div class="buttons">
+ {if $acceptURL}
+ <a href="{@$acceptURL}" class="deleteButton" title="{lang}{$languageCategory}.{$eventName}.accept{/lang}"><img src="{icon}checkS.png{/icon}" alt="{lang}{$languageCategory}.{$eventName}.accept{/lang}" longdesc="{if $declineURL}{lang}{$languageCategory}.{$eventName}.accept.sure{/lang}{/if}" /></a>
+ {/if}
+ {if $declineURL}
+ <a href="{@$declineURL}" class="deleteButton" title="{lang}{$languageCategory}.{$eventName}.decline{/lang}"><img src="{icon}deleteS.png{/icon}" alt="{lang}{$languageCategory}.{$eventName}.decline{/lang}" longdesc="{lang}{$languageCategory}.{$eventName}.decline.sure{/lang}" /></a>
+ {/if}
+ </div>
+ {/if}
+ <p class="itemListTitle">{@$notification->messageCache}</p>
+ </li>
+ {/foreach}
+ </ul>
+ </div>
+ <script type="text/javascript">
+ //<![CDATA[
+ document.observe('wcf:inlineDelete', function() {
+ if ($('outstandingNotificationsContainer') && !$('outstandingNotificationsContainer').down('li')) {
+ inlineDelete($('outstandingNotificationsContainer').down('.close'));
+ }
+ });
+ //]]>
+ </script>
\ No newline at end of file
--- /dev/null
+{include file="documentHeader"}
+<head>
+ <title>{lang}wcf.user.notification.title{/lang} - {lang}wcf.user.usercp{/lang} - {lang}{PAGE_TITLE}{/lang}</title>
+
+ {include file='headInclude' sandbox=false}
+ {include file='imageViewer'}
+ <script type="text/javascript" src="{@RELATIVE_WCF_DIR}js/MultiPagesLinks.class.js"></script>
+ <link rel="alternate" type="application/rss+xml" href="index.php?page=UserNotificationFeed&format=rss2" title="{lang}wcf.user.notification.feed{/lang} (RSS2)" />
+ <link rel="alternate" type="application/atom+xml" href="index.php?page=UserNotificationFeed&format=atom" title="{lang}wcf.user.notification.feed{/lang} (Atom)" />
+</head>
+<body{if $templateName|isset} id="tpl{$templateName|ucfirst}"{/if}>
+{include file='header' sandbox=false}
+
+<div id="main">
+ {include file="userCPHeader"}
+
+ <div class="border tabMenuContent">
+ <div class="container-1">
+ <h3 class="subHeadline">{lang}wcf.user.notification.title{/lang}</h3>
+ {if $notifications|count}
+ <div class="contentHeader">
+ {pages print=true assign=pagesLinks link="index.php?page=UserNotification&pageNo=%d"|concat:SID_ARG_2ND_NOT_ENCODED}
+ </div>
+
+ <div class="border titleBarPanel">
+ <div class="containerHead">
+ <h4>{lang}wcf.user.notification.stats{/lang}</h4>
+ </div>
+ </div>
+ <div class="border borderMarginRemove">
+ <table class="tableList">
+ <thead>
+ <tr class="tableHead">
+ <th class="columnIcon">
+ <div>
+ <span class="emptyHead">{lang}wcf.user.notification.icon{/lang}</span>
+ </div>
+ </th>
+ <th class="columnText">
+ <div>
+ <span class="emptyHead">{lang}wcf.user.notification.text{/lang}</span>
+ </div>
+ </th>
+ <th class="columnText">
+ <div>
+ <span class="emptyHead">{lang}wcf.user.notification.time{/lang}</span>
+ </div>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ {foreach from=$notifications item=notification}
+ {assign var=languageCategory value=$notification->event->languageCategory}
+ {assign var=eventName value=$notification->eventName}
+ <tr class="{cycle values='container-1,container-2'}">
+ <td class="columnIcon">
+ <img src="{icon}{$notification->event->icon}M.png{/icon}" alt="" />
+ </td>
+ <td class="columnText{if !$notification->confirmed} new{/if}">
+ <span>{@$notification->longOutput}</span>
+ {if !$notification->confirmed && $notification->event->requiresConfirmation && $notification->event->acceptURL}
+ {assign var=acceptURL value=$notification->event->getAcceptURL($notification)}
+ {assign var=declineURL value=$notification->event->getDeclineURL($notification)}
+ <div class="buttons" style="float: right;">
+ {if $acceptURL}
+ <a href="{@$acceptURL}" title="{lang}{$languageCategory}.{$eventName}.accept{/lang}"><img src="{icon}checkS.png{/icon}" alt="{lang}{$languageCategory}.{$eventName}.accept{/lang}" {if $declineURL}onclick="return confirm('{lang}{$languageCategory}.{$eventName}.accept.sure{/lang}');"{/if} /></a>
+ {/if}
+ {if $declineURL}
+ <a href="{@$declineURL}" title="{lang}{$languageCategory}.{$eventName}.decline{/lang}"><img src="{icon}deleteS.png{/icon}" alt="{lang}{$languageCategory}.{$eventName}.decline{/lang}" onclick="return confirm('{lang}{$languageCategory}.{$eventName}.accept.sure{/lang}');" /></a>
+ {/if}
+ </div>
+ {/if}
+ </td>
+ <td class="columnText">
+ <span>{@$notification->time|time}</span>
+ </td>
+ </tr>
+ {/foreach}
+ </tbody>
+ </table>
+ </div>
+
+ <div class="contentFooter">
+ {@$pagesLinks}
+ </div>
+ {else}
+ <p>{lang}wcf.user.notification.noNotifications{/lang}</p>
+ {/if}
+ </div>
+ </div>
+</div>
+
+{include file='footer' sandbox=false}
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="{@CHARSET}"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+ <title>{lang}wcf.user.notification.feed.title{/lang}</title>
+ <id>{@PAGE_URL}/</id>
+ <updated>{@'c'|gmdate:TIME_NOW}</updated>
+ <link href="{@PAGE_URL}/" />
+ <generator uri="http://www.woltlab.com/" version="{@WCF_VERSION}">
+ WoltLab Community Framework
+ </generator>
+ <subtitle>{lang}wcf.user.notification.feed.description{/lang}</subtitle>
+
+ {foreach from=$notifications item=notification}
+ <entry>
+ <title><![CDATA[{$notification->shortOutput}]]></title>
+ <id>{@PAGE_URL}/index.php?page=UserNotification&notificationID={@$notification->notificationID}</id>
+ <updated>{@'c'|gmdate:$notification->time}</updated>
+ <author>
+ <name>{$this->user->username}</name>
+ </author>
+ <content type="html"><![CDATA[{@$notification->longOutput}]]></content>
+ <link href="{@PAGE_URL}/index.php?page=UserNotification&notificationID={@$notification->notificationID}" />
+ </entry>
+ {/foreach}
+</feed>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="{@CHARSET}"?>
+<rss version="2.0">
+ <channel>
+ <title>{lang}wcf.user.notification.feed.title{/lang}</title>
+ <link>{@PAGE_URL}/</link>
+ <description>{lang}wcf.user.notification.feed.description{/lang}</description>
+
+ <pubDate>{@'r'|gmdate:TIME_NOW}</pubDate>
+ <lastBuildDate>{@'r'|gmdate:TIME_NOW}</lastBuildDate>
+ <generator>WoltLab Community Framework {@WCF_VERSION}</generator>
+ <ttl>60</ttl>
+
+ {foreach from=$notifications item=notification}
+ <item>
+ <title><![CDATA[{$notification->shortOutput}]]></title>
+ <author>{$this->user->username}</author>
+ <link>{@PAGE_URL}/index.php?page=UserNotification</link>
+ <guid>{@PAGE_URL}/index.php?page=UserNotification&notificationID={@$notification->notificationID}</guid>
+ <pubDate>{@'r'|gmdate:$notification->time}</pubDate>
+ <description><![CDATA[{@$notification->longOutput}]]></description>
+ </item>
+ {/foreach}
+ </channel>
+</rss>
\ No newline at end of file
--- /dev/null
+{include file="documentHeader"}
+<head>
+ <title>{lang}wcf.user.notification.settings{/lang} - {lang}wcf.user.usercp{/lang} - {lang}{PAGE_TITLE}{/lang}</title>
+ {include file='headInclude' sandbox=false}
+</head>
+<body{if $templateName|isset} id="tpl{$templateName|ucfirst}"{/if}>
+{include file='header' sandbox=false}
+
+<div id="main">
+
+ {capture append=userMessages}
+ {if $errorField}
+ <p class="error">{lang}wcf.global.form.error{/lang}</p>
+ {/if}
+
+ {if $success|isset}
+ <p class="success">{lang}wcf.user.edit.success{/lang}</p>
+ {/if}
+ {/capture}
+
+ {include file="userCPHeader"}
+
+ <form method="post" action="index.php?form=UserNotificationSettings">
+ <div class="border tabMenuContent">
+ <div class="container-1">
+ <h3 class="subHeadline">{lang}wcf.user.notification.settings{/lang}</h3>
+
+ <div class="border borderMarginRemove">
+ <table class="tableList">
+ {foreach from=$notificationObjectTypes key=typeName item=data}
+ {assign var=objectType value=$data.object}
+ {assign var=events value=$data.events}
+ {cycle name="eventRows" values='container-1,container-2' print=false advance=false reset=true}
+ <thead>
+ <tr class="tableHead">
+ <th class="columnObjectType">
+ <div>
+ <h3 class="emptyHead">{lang}wcf.user.notification.object.type.{$typeName}{/lang}</h3>
+ </div>
+ </th>
+ {foreach from=$notificationTypes key=notificationTypeName item=notificationType}
+ <th class="columnNotificationType columnIcon">
+ <div>
+ <span class="emptyHead"><img src="{icon}{$notificationType->getIcon()}S.png{/icon}" alt="{lang}wcf.user.notification.type.{$notificationTypeName}{/lang}" title="{lang}wcf.user.notification.type.{$notificationTypeName}{/lang}" /></span>
+ </div>
+ </th>
+ {/foreach}
+ </tr>
+ </thead>
+ <tbody>
+ {foreach from=$events key=eventName item=event}
+ <tr class="{cycle name="eventRows"}">
+ <td class="columnEvent columnText">
+ <p title="{$event->getDescription()}">{$event->getTitle()}</p>
+ <p class="smallFont">{$event->getDescription()}</p>
+ </td>
+ {foreach from=$event->supportedNotificationTypes key=supportedType item=supported}
+ <td class="columnNotificationType columnIcon">
+ <input type="checkbox" name="activeEventNotifications[{$typeName}][{$eventName}][{$supportedType}]"{if !$supported} disabled="disabled"{/if}{if $activeEventNotifications[$typeName][$eventName][$supportedType]} checked="checked"{/if} />
+ </td>
+ {/foreach}
+ </tr>
+ {/foreach}
+ </tbody>
+ {/foreach}
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="formSubmit">
+ {@SECURITY_TOKEN_INPUT_TAG}
+ {@SID_INPUT_TAG}
+ <input type="submit" accesskey="s" value="{lang}wcf.global.button.submit{/lang}" />
+ <input type="reset" accesskey="r" value="{lang}wcf.global.button.reset{/lang}" />
+ </div>
+ </form>
+
+</div>
+
+{include file='footer' sandbox=false}
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/usercp-menu.xsd">
+ <import>
+ <usercpmenuitem name="wcf.user.usercp.menu.link.settings.notification">
+ <link>index.php?form=UserNotificationSettings</link>
+ <parent>wcf.user.usercp.menu.link.settings</parent>
+ <options>module_user_notification</options>
+ </usercpmenuitem>
+ <usercpmenuitem name="wcf.user.usercp.menu.link.management.notification">
+ <link>index.php?page=UserNotification</link>
+ <parent>wcf.user.usercp.menu.link.management</parent>
+ <options>module_user_notification</options>
+ </usercpmenuitem>
+ </import>
+</data>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com/XSD/useroptions.xsd">
+ <import>
+ <options>
+ <option name="notificationMailToken">
+ <categoryname>hidden</categoryname>
+ <optiontype>text</optiontype>
+ <editable>4</editable>
+ <visible>4</visible>
+ </option>
+ </options>
+ </import>
+</data>
\ No newline at end of file