/** * Processes a list of notification objects. * * @param array<\wcf\data\user\notification\UserNotification> $notificationObjects * @return array */ public function processNotifications(array $notificationObjects) { // return an empty set if no notifications exist if (empty($notificationObjects)) { return array('count' => 0, 'notifications' => array()); } $authorIDs = $eventIDs = $notificationIDs = $objectTypes = array(); foreach ($notificationObjects as $notification) { // cache object types if (!isset($objectTypes[$notification->objectType])) { $objectTypes[$notification->objectType] = array('objectType' => $this->availableObjectTypes[$notification->objectType], 'objectIDs' => array(), 'objects' => array()); } $objectTypes[$notification->objectType]['objectIDs'][] = $notification->objectID; $eventIDs[] = $notification->eventID; $notificationIDs[] = $notification->notificationID; } // load authors $conditions = new PreparedStatementConditionBuilder(); $conditions->add("notificationID IN (?)", array($notificationIDs)); $sql = "SELECT\t\tnotificationID, authorID\n\t\t\tFROM\t\twcf" . WCF_N . "_user_notification_author\n\t\t\t" . $conditions . "\n\t\t\tORDER BY\ttime ASC"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); $authorIDs = $authorToNotification = array(); while ($row = $statement->fetchArray()) { if ($row['authorID']) { $authorIDs[] = $row['authorID']; } if (!isset($authorToNotification[$row['notificationID']])) { $authorToNotification[$row['notificationID']] = array(); } $authorToNotification[$row['notificationID']][] = $row['authorID']; } // load authors $authors = UserProfile::getUserProfiles($authorIDs); $unknownAuthor = new UserProfile(new User(null, array('userID' => null, 'username' => WCF::getLanguage()->get('wcf.user.guest')))); // load objects associated with each object type foreach ($objectTypes as $objectType => $objectData) { $objectTypes[$objectType]['objects'] = $objectData['objectType']->getObjectsByIDs($objectData['objectIDs']); } // load required events $eventList = new UserNotificationEventList(); $eventList->getConditionBuilder()->add("user_notification_event.eventID IN (?)", array($eventIDs)); $eventList->readObjects(); $eventObjects = $eventList->getObjects(); // build notification data $notifications = array(); $deleteNotifications = array(); foreach ($notificationObjects as $notification) { $object = $objectTypes[$notification->objectType]['objects'][$notification->objectID]; if ($object->__unknownNotificationObject) { $deleteNotifications[] = $notification; continue; } $className = $eventObjects[$notification->eventID]->className; $class = new $className($eventObjects[$notification->eventID]); $class->setObject($notification, $object, isset($authors[$notification->authorID]) ? $authors[$notification->authorID] : $unknownAuthor, $notification->additionalData); if (isset($authorToNotification[$notification->notificationID])) { $eventAuthors = array(); foreach ($authorToNotification[$notification->notificationID] as $userID) { if (!$userID) { $eventAuthors[0] = $unknownAuthor; } else { if (isset($authors[$userID])) { $eventAuthors[$userID] = $authors[$userID]; } } } if (!empty($eventAuthors)) { $class->setAuthors($eventAuthors); } } $data = array('authors' => count($class->getAuthors()), 'event' => $class, 'notificationID' => $notification->notificationID, 'time' => $notification->time); $data['confirmed'] = $notification->confirmTime > 0; $notifications[] = $data; } // check access foreach ($notifications as $index => $notificationData) { if (!$notificationData['event']->checkAccess()) { if ($notificationData['event']->deleteNoAccessNotification()) { $deleteNotifications[] = $notificationData['event']->getNotification(); } unset($notifications[$index]); } } if (!empty($deleteNotifications)) { $notificationAction = new UserNotificationAction($deleteNotifications, 'delete'); $notificationAction->executeAction(); // reset notification counter UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'userNotificationCount'); } return array('count' => count($notifications), 'notifications' => $notifications); }
/** * @see \wcf\system\cronjob\ICronjob::execute() */ public function execute(Cronjob $cronjob) { parent::execute($cronjob); // get user ids $userIDs = array(); $sql = "SELECT\tDISTINCT userID\n\t\t\tFROM\twcf" . WCF_N . "_user_notification\n\t\t\tWHERE\tmailNotified = ?\n\t\t\t\tAND time < ?\n\t\t\t\tAND confirmTime = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array(0, TIME_NOW - 3600 * 23, 0)); while ($row = $statement->fetchArray()) { $userIDs[] = $row['userID']; } if (empty($userIDs)) { return; } // get users $userList = new UserList(); $userList->setObjectIDs($userIDs); $userList->readObjects(); $users = $userList->getObjects(); // get notifications $conditions = new PreparedStatementConditionBuilder(); $conditions->add("notification.userID IN (?)", array($userIDs)); $conditions->add("notification.mailNotified = ?", array(0)); $conditions->add("notification.confirmTime = ?", array(0)); $sql = "SELECT\t\tnotification.*, notification_event.eventID, object_type.objectType\n\t\t\tFROM\t\twcf" . WCF_N . "_user_notification notification\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_user_notification_event notification_event\n\t\t\tON\t\t(notification_event.eventID = notification.eventID)\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_object_type object_type\n\t\t\tON\t\t(object_type.objectTypeID = notification_event.objectTypeID)\n\t\t\t" . $conditions . "\n\t\t\tORDER BY\tnotification.time"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); // mark notifications as done $conditions = new PreparedStatementConditionBuilder(); $conditions->add("userID IN (?)", array($userIDs)); $conditions->add("mailNotified = ?", array(0)); $sql = "UPDATE\twcf" . WCF_N . "_user_notification\n\t\t\tSET\tmailNotified = 1\n\t\t\t" . $conditions; $statement2 = WCF::getDB()->prepareStatement($sql); $statement2->execute($conditions->getParameters()); // collect data $eventsToUser = $objectTypes = $eventIDs = $notificationObjects = array(); $availableObjectTypes = UserNotificationHandler::getInstance()->getAvailableObjectTypes(); while ($row = $statement->fetchArray()) { if (!isset($eventsToUser[$row['userID']])) { $eventsToUser[$row['userID']] = array(); } $eventsToUser[$row['userID']][] = $row['notificationID']; // cache object types if (!isset($objectTypes[$row['objectType']])) { $objectTypes[$row['objectType']] = array('objectType' => $availableObjectTypes[$row['objectType']], 'objectIDs' => array(), 'objects' => array()); } $objectTypes[$row['objectType']]['objectIDs'][] = $row['objectID']; $eventIDs[] = $row['eventID']; $notificationObjects[$row['notificationID']] = new UserNotification(null, $row); } // load authors $conditions = new PreparedStatementConditionBuilder(); $conditions->add("notificationID IN (?)", array(array_keys($notificationObjects))); $sql = "SELECT\t\tnotificationID, authorID\n\t\t\tFROM\t\twcf" . WCF_N . "_user_notification_author\n\t\t\t" . $conditions . "\n\t\t\tORDER BY\ttime ASC"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); $authorIDs = $authorToNotification = array(); while ($row = $statement->fetchArray()) { if ($row['authorID']) { $authorIDs[] = $row['authorID']; } if (!isset($authorToNotification[$row['notificationID']])) { $authorToNotification[$row['notificationID']] = array(); } $authorToNotification[$row['notificationID']][] = $row['authorID']; } // load authors $authors = UserProfile::getUserProfiles($authorIDs); $unknownAuthor = new UserProfile(new User(null, array('userID' => null, 'username' => WCF::getLanguage()->get('wcf.user.guest')))); // load objects associated with each object type foreach ($objectTypes as $objectType => $objectData) { $objectTypes[$objectType]['objects'] = $objectData['objectType']->getObjectsByIDs($objectData['objectIDs']); } // load required events $eventList = new UserNotificationEventList(); $eventList->getConditionBuilder()->add("user_notification_event.eventID IN (?)", array($eventIDs)); $eventList->readObjects(); $eventObjects = $eventList->getObjects(); foreach ($eventsToUser as $userID => $events) { if (!isset($users[$userID])) { continue; } $user = $users[$userID]; // no notifications for disabled or banned users if ($user->activationCode) { continue; } if ($user->banned) { continue; } // add mail header $message = $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.header', array('user' => $user)); foreach ($events as $notificationID) { $notification = $notificationObjects[$notificationID]; $className = $eventObjects[$notification->eventID]->className; $class = new $className($eventObjects[$notification->eventID]); $class->setObject($notification, $objectTypes[$notification->objectType]['objects'][$notification->objectID], isset($authors[$notification->authorID]) ? $authors[$notification->authorID] : $unknownAuthor, $notification->additionalData); $class->setLanguage($user->getLanguage()); if (isset($authorToNotification[$notification->notificationID])) { $eventAuthors = array(); foreach ($authorToNotification[$notification->notificationID] as $userID) { if (!$userID) { $eventAuthors[0] = $unknownAuthor; } else { if (isset($authors[$userID])) { $eventAuthors[$userID] = $authors[$userID]; } } } if (!empty($eventAuthors)) { $class->setAuthors($eventAuthors); } } $message .= "\n\n"; $message .= $class->getEmailMessage('daily'); } // append notification mail footer $token = $user->notificationMailToken; if (!$token) { // generate token if not present $token = mb_substr(StringUtil::getHash(serialize(array($user->userID, StringUtil::getRandomID()))), 0, 20); $editor = new UserEditor($user); $editor->update(array('notificationMailToken' => $token)); } $message .= "\n\n"; $message .= $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.daily.footer', array('user' => $user, 'token' => $token)); // build mail $mail = new Mail(array($user->username => $user->email), $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.daily.subject', array('count' => count($events))), $message); $mail->setLanguage($user->getLanguage()); $mail->send(); } }