From 650a2759e4ea5dfc09aec409f8e927c255202642 Mon Sep 17 00:00:00 2001 From: ECYaz Date: Fri, 7 Aug 2026 07:20:02 -0400 Subject: [PATCH] Deliver subscription notifications through the phpBB notification system Titania subscription events were emailed directly through the legacy messenger, invisible to the board's notification bell and the UCP notification options. Route them through the notification manager instead: five data-driven notification types (posted, contribution, queue, queue_move sharing the queue option, attention) select their recipients from the existing watch table and render the existing email templates through the email method, so watchers now get board and/or email delivery per their UCP preferences. The watch table remains the source of what a user subscribed to; the subscribe UI and UCP subscriptions module are unchanged. To keep subscribing meaning mail-me for everyone, a migration adds an email preference row for every existing watcher (the board method delivers by default without a row) and new users get default email rows for the Titania types at registration, exactly like the core does for its post and topic types. The attention and no-validation revision dispatches move after their rows are inserted, since the notification needs the item id. Deleting a post, revision, queue item or contribution now also deletes the notifications that point at it. --- config/services.yml | 52 +++++- controller/contribution/revision.php | 19 +- event/main_listener.php | 46 +++++ ext.php | 76 ++++++++ includes/objects/attention.php | 45 +++-- includes/objects/attention_types/post.php | 37 ++-- includes/objects/contribution.php | 18 +- includes/objects/post.php | 22 ++- includes/objects/queue.php | 38 +++- includes/objects/revision.php | 38 ++-- language/en/notifications.php | 57 ++++++ migrations/notifications_integration.php | 138 +++++++++++++++ notification/type/attention.php | 60 +++++++ notification/type/base.php | 205 ++++++++++++++++++++++ notification/type/contribution.php | 36 ++++ notification/type/posted.php | 53 ++++++ notification/type/queue.php | 59 +++++++ notification/type/queue_move.php | 41 +++++ posting.php | 45 +++-- subscriptions.php | 171 ++++-------------- 20 files changed, 1049 insertions(+), 207 deletions(-) create mode 100644 language/en/notifications.php create mode 100644 migrations/notifications_integration.php create mode 100644 notification/type/attention.php create mode 100644 notification/type/base.php create mode 100644 notification/type/contribution.php create mode 100644 notification/type/posted.php create mode 100644 notification/type/queue.php create mode 100644 notification/type/queue_move.php diff --git a/config/services.yml b/config/services.yml index b0343ebc5..7312bc6e4 100644 --- a/config/services.yml +++ b/config/services.yml @@ -334,6 +334,7 @@ services: - '@phpbb.titania.message' - '@phpbb.titania.access' - '@phpbb.titania.subscriptions' + - '@path_helper' - '@phpbb.titania.attachment.operator' phpbb.titania.queue.stats: @@ -431,18 +432,61 @@ services: tags: - { name: titania.contribution.type } + phpbb.titania.notification.type.base: + abstract: true + class: phpbb\titania\notification\type\base + parent: notification.type.base + calls: + - [set_user_loader, ['@user_loader']] + + phpbb.titania.notification.type.posted: + class: phpbb\titania\notification\type\posted + shared: false + parent: phpbb.titania.notification.type.base + tags: + - { name: notification.type } + + phpbb.titania.notification.type.contribution: + class: phpbb\titania\notification\type\contribution + shared: false + parent: phpbb.titania.notification.type.base + tags: + - { name: notification.type } + + phpbb.titania.notification.type.queue: + class: phpbb\titania\notification\type\queue + shared: false + parent: phpbb.titania.notification.type.base + calls: + - [set_type_collection, ['@phpbb.titania.contribution.type.collection']] + tags: + - { name: notification.type } + + phpbb.titania.notification.type.queue_move: + class: phpbb\titania\notification\type\queue_move + shared: false + parent: phpbb.titania.notification.type.queue + tags: + - { name: notification.type } + + phpbb.titania.notification.type.attention: + class: phpbb\titania\notification\type\attention + shared: false + parent: phpbb.titania.notification.type.base + calls: + - [set_type_collection, ['@phpbb.titania.contribution.type.collection']] + tags: + - { name: notification.type } + phpbb.titania.subscriptions: class: phpbb\titania\subscriptions arguments: - '@dbal.conn' - - '@config' - '@request' - '@template' - '@user' - '@path_helper' - - '%tables.users%' - - '%core.root_path%' - - '%core.php_ext%' + - '@notification_manager' phpbb.titania.sync: class: phpbb\titania\sync diff --git a/controller/contribution/revision.php b/controller/contribution/revision.php index 72a8bb7ea..ce400d181 100644 --- a/controller/contribution/revision.php +++ b/controller/contribution/revision.php @@ -270,13 +270,18 @@ public function add($contrib_type, $contrib) 'U_VIEW' => $this->queue->get_url(), ); - $this->subscriptions->send_notifications( - ext::TITANIA_QUEUE, - $this->contrib->contrib_type, - 'subscribe_notify_forum', - $email_vars, - $this->user->data['user_id'] - ); + $this->subscriptions->send_notifications('queue', array( + 'item_id' => $this->queue->queue_id, + 'item_parent_id' => $this->contrib->contrib_id, + 'watch' => array(array(ext::TITANIA_QUEUE, $this->contrib->contrib_type)), + 'exclude_user' => $this->user->data['user_id'], + 'lang_key' => 'NOTIFICATION_TITANIA_QUEUE_NEW', + 'reference' => $this->contrib->contrib_name . ' ' . $this->revision->revision_version, + 'url' => $email_vars['U_VIEW'], + 'email_template' => 'subscribe_notify_forum', + 'email_vars' => $email_vars, + 'actor_id' => $this->user->data['user_id'], + )); } redirect($this->contrib->get_url()); } diff --git a/event/main_listener.php b/event/main_listener.php index 11227cac2..7a67b0bec 100644 --- a/event/main_listener.php +++ b/event/main_listener.php @@ -103,6 +103,8 @@ static public function getSubscribedEvents() { return array( 'core.permissions' => 'add_permissions', + 'core.user_setup' => 'load_language', + 'core.user_add_modify_notifications_data' => 'add_notifications_data', 'kernel.request' => array(array('startup', -1)), 'core.page_header_after' => 'overwrite_template_vars', 'core.text_formatter_s9e_configure_after' => 'inject_bbcode_code_lang', @@ -192,6 +194,50 @@ public function add_permissions($event) )); } + /** + * Load the notification language file on every page, so the notification + * dropdown and the UCP notification options can render Titania's types. + * + * @param data $event + */ + public function load_language($event) + { + $lang_set_ext = $event['lang_set_ext']; + $lang_set_ext[] = array( + 'ext_name' => 'phpbb/titania', + 'lang_set' => 'notifications', + ); + $event['lang_set_ext'] = $lang_set_ext; + } + + /** + * Give new users email delivery for the Titania notification types by + * default, like the core does for the post and topic types, so + * subscribing keeps its historical mail-me meaning. + * + * @param data $event + */ + public function add_notifications_data($event) + { + $notifications_data = $event['notifications_data']; + + foreach (ext::get_notification_types() as $type) + { + // queue_move shares the queue type's preferences + if ($type === 'phpbb.titania.notification.type.queue_move') + { + continue; + } + + $notifications_data[] = array( + 'item_type' => $type, + 'method' => 'notification.method.email', + ); + } + + $event['notifications_data'] = $notifications_data; + } + public function startup($event) { if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST || diff --git a/ext.php b/ext.php index 389805fe8..aef4f9296 100644 --- a/ext.php +++ b/ext.php @@ -105,4 +105,80 @@ public static function get_filtered_repository_branches(): array { return [40]; } + + /** + * The notification types this extension provides + * + * @return array Array of notification type service names + */ + public static function get_notification_types(): array + { + return [ + 'phpbb.titania.notification.type.posted', + 'phpbb.titania.notification.type.contribution', + 'phpbb.titania.notification.type.queue', + 'phpbb.titania.notification.type.queue_move', + 'phpbb.titania.notification.type.attention', + ]; + } + + /** + * {@inheritdoc} + */ + public function enable_step($old_state) + { + if ($old_state === false) + { + $notification_manager = $this->container->get('notification_manager'); + + foreach (self::get_notification_types() as $type) + { + $notification_manager->enable_notifications($type); + } + + return 'notifications'; + } + + return parent::enable_step($old_state); + } + + /** + * {@inheritdoc} + */ + public function disable_step($old_state) + { + if ($old_state === false) + { + $notification_manager = $this->container->get('notification_manager'); + + foreach (self::get_notification_types() as $type) + { + $notification_manager->disable_notifications($type); + } + + return 'notifications'; + } + + return parent::disable_step($old_state); + } + + /** + * {@inheritdoc} + */ + public function purge_step($old_state) + { + if ($old_state === false) + { + $notification_manager = $this->container->get('notification_manager'); + + foreach (self::get_notification_types() as $type) + { + $notification_manager->purge_notifications($type); + } + + return 'notifications'; + } + + return parent::purge_step($old_state); + } } diff --git a/includes/objects/attention.php b/includes/objects/attention.php index a7398e087..67c0f104a 100644 --- a/includes/objects/attention.php +++ b/includes/objects/attention.php @@ -91,8 +91,12 @@ public function check_auth() public function submit() { - // Subscriptions - if (!$this->attention_id) + $is_new = !$this->attention_id; + + parent::submit(); + + // Subscriptions; sent after the parent submit so the attention id exists + if ($is_new) { $u_view = $this->controller_helper->route('phpbb.titania.manage.attention.redirect', array( 'type' => $this->attention_type, @@ -102,16 +106,35 @@ public function submit() 'NAME' => $this->attention_title, 'U_VIEW' => $this->path_helper->strip_url_params($u_view, 'sid'), ); - $this->subscriptions->send_notifications( - ext::TITANIA_ATTENTION, - 0, - 'subscribe_notify', - $email_vars, - $this->attention_poster_id - ); - } - parent::submit(); + switch ($this->attention_type) + { + case ext::TITANIA_ATTENTION_REPORTED: + $lang_key = 'NOTIFICATION_TITANIA_ATTENTION_REPORT'; + break; + + case ext::TITANIA_ATTENTION_UNAPPROVED: + $lang_key = 'NOTIFICATION_TITANIA_ATTENTION_UNAPPROVED'; + break; + + default: + $lang_key = 'NOTIFICATION_TITANIA_ATTENTION'; + break; + } + + $this->subscriptions->send_notifications('attention', array( + 'item_id' => $this->attention_id, + 'item_parent_id' => $this->attention_object_id, + 'watch' => array(array(ext::TITANIA_ATTENTION, 0)), + 'exclude_user' => $this->attention_poster_id, + 'lang_key' => $lang_key, + 'reference' => $this->attention_title, + 'url' => $email_vars['U_VIEW'], + 'email_template' => 'subscribe_notify', + 'email_vars' => $email_vars, + 'actor_id' => $this->attention_requester, + )); + } } /** diff --git a/includes/objects/attention_types/post.php b/includes/objects/attention_types/post.php index 8cfe2a54d..de8b8d31b 100644 --- a/includes/objects/attention_types/post.php +++ b/includes/objects/attention_types/post.php @@ -273,10 +273,12 @@ protected function approve_post() $message_vars = array( 'U_VIEW' => $this->path_helper->strip_url_params($u_view, 'sid'), ); - $object_type = array(ext::TITANIA_TOPIC, ext::TITANIA_SUPPORT); - $object_id = array($this->post->topic_id, $this->post->topic->parent_id); + $watch = array( + array(ext::TITANIA_TOPIC, $this->post->topic_id), + array(ext::TITANIA_SUPPORT, $this->post->topic->parent_id), + ); - $this->send_notifications($object_type, $object_id, 'subscribe_notify_contrib', $message_vars); + $this->send_notifications($watch, 'NOTIFICATION_TITANIA_REPLY_CONTRIB', 'subscribe_notify_contrib', $message_vars); } } @@ -296,20 +298,21 @@ protected function approve_topic() if ($this->post->topic->topic_last_post_id == $this->post->post_id) { $message_vars = array('U_VIEW' => $this->post->topic->get_url()); + $watch = array(array($this->post->post_type, $this->post->topic->parent_id)); - $this->send_notifications($this->post->post_type, $this->post->topic->parent_id, 'subscribe_notify_forum_contrib', $message_vars); + $this->send_notifications($watch, 'NOTIFICATION_TITANIA_TOPIC_CONTRIB', 'subscribe_notify_forum_contrib', $message_vars); } } /** * Send notifications. * - * @param int|array $object_type - * @param int|array $object_id + * @param array $watch Array of array(watch_object_type, watch_object_id) pairs + * @param string $lang_key Language key for the board notification title * @param string $email_template * @param array $message_vars */ - public function send_notifications($object_type, $object_id, $email_template, $message_vars) + public function send_notifications($watch, $lang_key, $email_template, $message_vars) { $this->load_contrib_object(); @@ -318,13 +321,19 @@ public function send_notifications($object_type, $object_id, $email_template, $m 'CONTRIB_NAME' => $this->contrib->contrib_name, )); - $this->subscriptions->send_notifications( - $object_type, - $object_id, - $email_template, - $message_vars, - $this->post->post_user_id - ); + $this->subscriptions->send_notifications('posted', array( + 'item_id' => $this->post->post_id, + 'item_parent_id' => $this->post->topic_id, + 'watch' => $watch, + 'exclude_user' => $this->post->post_user_id, + 'lang_key' => $lang_key, + 'lang_params' => array($this->contrib->contrib_name), + 'reference' => $this->post->topic->topic_subject, + 'url' => $message_vars['U_VIEW'], + 'email_template' => $email_template, + 'email_vars' => $message_vars, + 'actor_id' => $this->post->post_user_id, + )); } /** diff --git a/includes/objects/contribution.php b/includes/objects/contribution.php index c4b74f3d0..651a74f01 100644 --- a/includes/objects/contribution.php +++ b/includes/objects/contribution.php @@ -2313,12 +2313,28 @@ public function delete() // Change the status to new (handles resetting counts) $this->change_status(ext::TITANIA_CONTRIB_NEW); - // Remove any attention items + // Remove any attention items and their notifications + $attention_ids = array(); + $sql = 'SELECT attention_id FROM ' . TITANIA_ATTENTION_TABLE . ' + WHERE attention_object_type = ' . ext::TITANIA_CONTRIB . ' + AND attention_object_id = ' . $this->contrib_id; + $result = phpbb::$db->sql_query($sql); + while ($row = phpbb::$db->sql_fetchrow($result)) + { + $attention_ids[] = (int) $row['attention_id']; + } + phpbb::$db->sql_freeresult($result); + $sql = 'DELETE FROM ' . TITANIA_ATTENTION_TABLE . ' WHERE attention_object_type = ' . ext::TITANIA_CONTRIB . ' AND attention_object_id = ' . $this->contrib_id; phpbb::$db->sql_query($sql); + if (!empty($attention_ids)) + { + phpbb::$container->get('notification_manager')->delete_notifications('phpbb.titania.notification.type.attention', $attention_ids); + } + // Delete the release topic if ($this->contrib_release_topic_id) { diff --git a/includes/objects/post.php b/includes/objects/post.php index 15a0b1742..1ef265450 100644 --- a/includes/objects/post.php +++ b/includes/objects/post.php @@ -765,12 +765,32 @@ public function hard_delete() // @todo remove attachments and other things - // Remove any attention items + // Remove any attention items and their notifications + $attention_ids = array(); + $sql = 'SELECT attention_id FROM ' . TITANIA_ATTENTION_TABLE . ' + WHERE attention_object_type = ' . ext::TITANIA_POST . ' + AND attention_object_id = ' . $this->post_id; + $result = phpbb::$db->sql_query($sql); + while ($row = phpbb::$db->sql_fetchrow($result)) + { + $attention_ids[] = (int) $row['attention_id']; + } + phpbb::$db->sql_freeresult($result); + $sql = 'DELETE FROM ' . TITANIA_ATTENTION_TABLE . ' WHERE attention_object_type = ' . ext::TITANIA_POST . ' AND attention_object_id = ' . $this->post_id; phpbb::$db->sql_query($sql); + // Remove any notifications for this post and its attention items + $notification_manager = phpbb::$container->get('notification_manager'); + $notification_manager->delete_notifications('phpbb.titania.notification.type.posted', $this->post_id); + + if (!empty($attention_ids)) + { + $notification_manager->delete_notifications('phpbb.titania.notification.type.attention', $attention_ids); + } + // Decrement the user's postcount if we must if (!$this->post_deleted && $this->post_approved && in_array($this->post_type, titania::$config->increment_postcount)) { diff --git a/includes/objects/queue.php b/includes/objects/queue.php index 0d9dc6c5b..09c90196d 100644 --- a/includes/objects/queue.php +++ b/includes/objects/queue.php @@ -323,6 +323,12 @@ public function delete() WHERE revision_id = ' . $this->revision_id; phpbb::$db->sql_query($sql); + // Remove any notifications for this queue item + phpbb::$container->get('notification_manager')->delete_notifications( + array('phpbb.titania.notification.type.queue', 'phpbb.titania.notification.type.queue_move'), + $this->queue_id + ); + // Assplode parent::delete(); } @@ -353,13 +359,19 @@ public function move($new_status, \phpbb\titania\tags $tags) 'CATEGORY_NAME' => $to, 'U_VIEW_QUEUE' => $path_helper->strip_url_params($u_view_queue, 'sid'), ); - $this->subscriptions->send_notifications( - ext::TITANIA_QUEUE_TAG, - $new_status, - 'new_contrib_queue_cat', - $vars, - phpbb::$user->data['user_id'] - ); + $this->subscriptions->send_notifications('queue_move', array( + 'item_id' => $this->queue_id, + 'item_parent_id' => $this->contrib_id, + 'watch' => array(array(ext::TITANIA_QUEUE_TAG, $new_status)), + 'exclude_user' => phpbb::$user->data['user_id'], + 'lang_key' => 'NOTIFICATION_TITANIA_QUEUE_MOVE', + 'lang_params' => array($to), + 'reference' => $contrib->contrib_name, + 'url' => $vars['U_VIEW_QUEUE'], + 'email_template' => 'new_contrib_queue_cat', + 'email_vars' => $vars, + 'actor_id' => phpbb::$user->data['user_id'], + )); } public function in_progress() @@ -461,7 +473,17 @@ public function approve($public_notes, $robot_user_id = 0) 'NAME' => $contrib->contrib_name, 'U_VIEW' => $contrib->get_url(), ); - $this->subscriptions->send_notifications(ext::TITANIA_CONTRIB, $this->contrib_id, 'subscribe_notify', $email_vars); + $this->subscriptions->send_notifications('contribution', array( + 'item_id' => $revision->revision_id, + 'item_parent_id' => $this->contrib_id, + 'watch' => array(array(ext::TITANIA_CONTRIB, $this->contrib_id)), + 'lang_key' => 'NOTIFICATION_TITANIA_CONTRIB_UPDATED', + 'lang_params' => array($revision->revision_version), + 'reference' => $contrib->contrib_name, + 'url' => $email_vars['U_VIEW'], + 'email_template' => 'subscribe_notify', + 'email_vars' => $email_vars, + )); $this->trash_queue_topic(); } diff --git a/includes/objects/revision.php b/includes/objects/revision.php index ca80bee86..10c5a6247 100644 --- a/includes/objects/revision.php +++ b/includes/objects/revision.php @@ -297,6 +297,8 @@ public function display($tpl_block = 'revisions', $show_queue = false, $all_vers */ public function submit() { + $notify_subscribers = false; + if (!$this->revision_id) { // Update the contrib_last_update if required here @@ -312,17 +314,8 @@ public function submit() WHERE contrib_id = ' . $this->contrib_id; phpbb::$db->sql_query($sql); - // Subscriptions - $email_vars = array( - 'NAME' => $this->contrib->contrib_name, - 'U_VIEW' => $this->contrib->get_url(), - ); - $this->subscriptions->send_notifications( - ext::TITANIA_CONTRIB, - $this->contrib_id, - 'subscribe_notify', - $email_vars - ); + // Notify the subscribers once the revision row exists + $notify_subscribers = true; } } else if (sizeof($this->phpbb_versions)) @@ -378,6 +371,26 @@ public function submit() { $this->contrib->update_release_topic(); } + + // Subscriptions + if ($notify_subscribers) + { + $email_vars = array( + 'NAME' => $this->contrib->contrib_name, + 'U_VIEW' => $this->contrib->get_url(), + ); + $this->subscriptions->send_notifications('contribution', array( + 'item_id' => $this->revision_id, + 'item_parent_id' => $this->contrib_id, + 'watch' => array(array(ext::TITANIA_CONTRIB, $this->contrib_id)), + 'lang_key' => 'NOTIFICATION_TITANIA_CONTRIB_UPDATED', + 'lang_params' => array($this->revision_version), + 'reference' => $this->contrib->contrib_name, + 'url' => $email_vars['U_VIEW'], + 'email_template' => 'subscribe_notify', + 'email_vars' => $email_vars, + )); + } } /** @@ -590,6 +603,9 @@ public function delete() // $translations = new titania_attachment(TITANIA_TRANSLATION, $this->revision_id); // $attachment->delete_all(); + // Remove any notifications for this revision + phpbb::$container->get('notification_manager')->delete_notifications('phpbb.titania.notification.type.contribution', $this->revision_id); + // Self-destruct parent::delete(); } diff --git a/language/en/notifications.php b/language/en/notifications.php new file mode 100644 index 000000000..d8a016a9a --- /dev/null +++ b/language/en/notifications.php @@ -0,0 +1,57 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +/** +* DO NOT CHANGE +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +if (empty($lang) || !is_array($lang)) +{ + $lang = array(); +} + +// DEVELOPERS PLEASE NOTE +// +// All language files should use UTF-8 as their encoding and the files must not contain a BOM. +// +// Placeholders can now contain order information, e.g. instead of +// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows +// translators to re-order the output of data while ensuring it remains correct +// +// You do not need this where single placeholders are used, e.g. 'Message %d' is fine +// equally where a string contains only two placeholders which are used to wrap text +// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine + +$lang = array_merge($lang, array( + 'NOTIFICATION_GROUP_TITANIA' => 'Customisation Database', + + 'NOTIFICATION_TYPE_TITANIA_POSTED' => 'Someone posts in a subscribed topic or support area', + 'NOTIFICATION_TYPE_TITANIA_CONTRIBUTION' => 'A new version of a subscribed contribution is released', + 'NOTIFICATION_TYPE_TITANIA_QUEUE' => 'A watched validation queue changes', + 'NOTIFICATION_TYPE_TITANIA_ATTENTION' => 'Content is reported or awaits approval', + + 'NOTIFICATION_TITANIA_REPLY' => 'Reply from %1$s to the topic:', + 'NOTIFICATION_TITANIA_REPLY_CONTRIB' => 'Reply from %1$s in the support area of %2$s to the topic:', + 'NOTIFICATION_TITANIA_TOPIC' => 'New topic from %1$s:', + 'NOTIFICATION_TITANIA_TOPIC_CONTRIB' => 'New topic from %1$s in the support area of %2$s:', + 'NOTIFICATION_TITANIA_CONTRIB_UPDATED' => 'New version %1$s released for the contribution:', + 'NOTIFICATION_TITANIA_QUEUE_NEW' => 'New queue item:', + 'NOTIFICATION_TITANIA_QUEUE_MOVE' => 'Queue item moved to %1$s:', + 'NOTIFICATION_TITANIA_ATTENTION' => 'Needs attention:', + 'NOTIFICATION_TITANIA_ATTENTION_REPORT' => 'Reported:', + 'NOTIFICATION_TITANIA_ATTENTION_UNAPPROVED' => 'Awaiting approval:', +)); diff --git a/migrations/notifications_integration.php b/migrations/notifications_integration.php new file mode 100644 index 000000000..3e610e6c9 --- /dev/null +++ b/migrations/notifications_integration.php @@ -0,0 +1,138 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\titania\migrations; + +use phpbb\titania\ext; + +/** +* Seed notification preferences for existing subscribers. +* +* The legacy dispatcher emailed every watcher. The notification system's +* default delivery for users without preference rows is the board method only, +* so existing subscribers would silently stop receiving emails. Give every +* current watcher explicit board + email preferences for the notification +* types their subscriptions map to; new subscribers from here on get the +* standard core defaults. +*/ +class notifications_integration extends base +{ + static public function depends_on() + { + return array('\phpbb\titania\migrations\release_1_1_0'); + } + + public function update_data() + { + return array( + array('custom', array(array($this, 'seed_user_notifications'))), + ); + } + + /** + * Seed user_notifications rows chunk by chunk. + * + * @param mixed $start Offset carried between calls by the migrator + * @return mixed True when done, else the next offset + */ + public function seed_user_notifications($start) + { + $limit = 500; + $start = (int) $start; + + $option_map = array( + ext::TITANIA_CONTRIB => 'phpbb.titania.notification.type.contribution', + ext::TITANIA_SUPPORT => 'phpbb.titania.notification.type.posted', + ext::TITANIA_TOPIC => 'phpbb.titania.notification.type.posted', + ext::TITANIA_QUEUE_DISCUSSION => 'phpbb.titania.notification.type.posted', + ext::TITANIA_QUEUE => 'phpbb.titania.notification.type.queue', + ext::TITANIA_QUEUE_TAG => 'phpbb.titania.notification.type.queue', + ext::TITANIA_ATTENTION => 'phpbb.titania.notification.type.attention', + ); + + $watch_table = $this->get_titania_table_prefix() . 'watch'; + + $sql = 'SELECT DISTINCT w.watch_user_id, w.watch_object_type + FROM ' . $watch_table . ' w, ' . $this->table_prefix . 'users u + WHERE w.watch_user_id = u.user_id + AND w.watch_type = ' . \phpbb\titania\subscriptions::EMAIL . ' + ORDER BY w.watch_user_id, w.watch_object_type'; + $result = $this->db->sql_query_limit($sql, $limit, $start); + + $row_count = 0; + $wanted = array(); + while ($row = $this->db->sql_fetchrow($result)) + { + $row_count++; + + if (isset($option_map[$row['watch_object_type']])) + { + $wanted[(int) $row['watch_user_id']][$option_map[$row['watch_object_type']]] = true; + } + } + $this->db->sql_freeresult($result); + + if (!$row_count) + { + return true; + } + + if (!empty($wanted)) + { + // Users who already have a preference row for a type keep it untouched + $sql = 'SELECT user_id, item_type, method + FROM ' . $this->table_prefix . 'user_notifications + WHERE item_id = 0 + AND ' . $this->db->sql_in_set('user_id', array_keys($wanted)) . ' + AND ' . $this->db->sql_in_set('item_type', array_values($option_map)); + $result = $this->db->sql_query($sql); + + $existing = array(); + while ($row = $this->db->sql_fetchrow($result)) + { + $existing[(int) $row['user_id']][$row['item_type']] = true; + } + $this->db->sql_freeresult($result); + + // The board method delivers by default without a row; an explicit + // email row is all that is needed, like the rows user registration + // creates for the post and topic types. + $insert = array(); + foreach ($wanted as $user_id => $options) + { + foreach ($options as $option => $null) + { + if (isset($existing[$user_id][$option])) + { + continue; + } + + $insert[] = array( + 'item_type' => $option, + 'item_id' => 0, + 'user_id' => $user_id, + 'method' => 'notification.method.email', + 'notify' => 1, + ); + } + } + + if (!empty($insert)) + { + $this->db->sql_multi_insert($this->table_prefix . 'user_notifications', $insert); + } + } + + return ($row_count == $limit) ? $start + $limit : true; + } +} diff --git a/notification/type/attention.php b/notification/type/attention.php new file mode 100644 index 000000000..9b9990df7 --- /dev/null +++ b/notification/type/attention.php @@ -0,0 +1,60 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\titania\notification\type; + +/** +* A new attention item (report or content needing approval) was created. +*/ +class attention extends base +{ + /** @var \phpbb\titania\contribution\type\collection */ + protected $type_collection; + + /** + * {@inheritdoc} + */ + static public $notification_option = array( + 'lang' => 'NOTIFICATION_TYPE_TITANIA_ATTENTION', + 'group' => 'NOTIFICATION_GROUP_TITANIA', + ); + + /** + * Set the contribution type collection. + * + * @param \phpbb\titania\contribution\type\collection $type_collection + */ + public function set_type_collection(\phpbb\titania\contribution\type\collection $type_collection) + { + $this->type_collection = $type_collection; + } + + /** + * {@inheritdoc} + */ + public function get_type() + { + return 'phpbb.titania.notification.type.attention'; + } + + /** + * {@inheritdoc} + * + * Mirrors the attention page's own access check. + */ + public function is_available() + { + return $this->auth->acl_gets('u_titania_mod_contrib_mod', 'u_titania_mod_post_mod') + || count($this->type_collection->find_authed('moderate')) > 0; + } +} diff --git a/notification/type/base.php b/notification/type/base.php new file mode 100644 index 000000000..6021167c5 --- /dev/null +++ b/notification/type/base.php @@ -0,0 +1,205 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\titania\notification\type; + +/** +* Base class for Titania notification types. +* +* All Titania subscription events are data driven: the dispatcher passes the +* watch pairs to select the recipients from, the language key and parameters +* for the board notification, the url, and the email template with its +* variables. Subclasses only differ in their type name, their UCP option and +* their availability. +*/ +abstract class base extends \phpbb\notification\type\base +{ + /** @var \phpbb\user_loader */ + protected $user_loader; + + /** + * Set the user loader (used for actor avatars and names) + * + * @param \phpbb\user_loader $user_loader + */ + public function set_user_loader(\phpbb\user_loader $user_loader) + { + $this->user_loader = $user_loader; + } + + /** + * The item type the user's notification preferences are stored under. + * Types sharing a UCP option (via $notification_option['id']) share it. + * + * @return string + */ + protected function get_option_type() + { + if (static::$notification_option !== false && isset(static::$notification_option['id'])) + { + return static::$notification_option['id']; + } + return $this->get_type(); + } + + /** + * {@inheritdoc} + */ + static public function get_item_id($type_data) + { + return (int) $type_data['item_id']; + } + + /** + * {@inheritdoc} + */ + static public function get_item_parent_id($type_data) + { + return (isset($type_data['item_parent_id'])) ? (int) $type_data['item_parent_id'] : 0; + } + + /** + * Find the users subscribed to the given watch pairs. + * + * @param array $type_data Expects 'watch' (array of array(object_type, object_id) + * pairs) and optionally 'exclude_user'. + * @param array $options + * @return array + */ + public function find_users_for_notification($type_data, $options = array()) + { + $options = array_merge(array( + 'ignore_users' => array(), + ), $options); + + // The watch table constant only exists once Titania's common.php ran, + // which is the case on every page that dispatches a notification. + if (empty($type_data['watch']) || !defined('TITANIA_WATCH_TABLE')) + { + return array(); + } + + $sql_objects = array(); + foreach ($type_data['watch'] as $watch) + { + $sql_objects[] = '(watch_object_type = ' . (int) $watch[0] . ' + AND watch_object_id = ' . (int) $watch[1] . ')'; + } + + $sql = 'SELECT watch_user_id + FROM ' . TITANIA_WATCH_TABLE . ' + WHERE (' . implode(' OR ', $sql_objects) . ')' . + ((!empty($type_data['exclude_user'])) ? ' AND watch_user_id <> ' . (int) $type_data['exclude_user'] : ''); + $result = $this->db->sql_query($sql); + + $users = array(); + while ($row = $this->db->sql_fetchrow($result)) + { + $users[(int) $row['watch_user_id']] = true; + } + $this->db->sql_freeresult($result); + + if (empty($users)) + { + return array(); + } + $users = array_keys($users); + sort($users); + + return $this->check_user_notification_options($users, array_merge($options, array( + 'item_type' => $this->get_option_type(), + ))); + } + + /** + * {@inheritdoc} + */ + public function create_insert_array($type_data, $pre_create_data = array()) + { + $this->set_data('lang_key', $type_data['lang_key']); + $this->set_data('lang_params', (isset($type_data['lang_params'])) ? $type_data['lang_params'] : array()); + $this->set_data('reference', (isset($type_data['reference'])) ? $type_data['reference'] : ''); + $this->set_data('url', (isset($type_data['url'])) ? $type_data['url'] : ''); + $this->set_data('email_template', $type_data['email_template']); + $this->set_data('email_vars', (isset($type_data['email_vars'])) ? $type_data['email_vars'] : array()); + $this->set_data('actor_id', (isset($type_data['actor_id'])) ? (int) $type_data['actor_id'] : 0); + + parent::create_insert_array($type_data, $pre_create_data); + } + + /** + * {@inheritdoc} + */ + public function get_title() + { + $params = $this->get_data('lang_params'); + + return $this->language->lang_array($this->get_data('lang_key'), (is_array($params)) ? $params : array()); + } + + /** + * {@inheritdoc} + */ + public function get_reference() + { + $reference = $this->get_data('reference'); + + return ($reference) ? $this->language->lang('NOTIFICATION_REFERENCE', $reference) : ''; + } + + /** + * {@inheritdoc} + */ + public function get_url() + { + return $this->get_data('url'); + } + + /** + * {@inheritdoc} + */ + public function get_email_template() + { + return '@phpbb_titania/' . $this->get_data('email_template'); + } + + /** + * {@inheritdoc} + */ + public function get_email_template_variables() + { + $vars = $this->get_data('email_vars'); + + return (is_array($vars)) ? $vars : array(); + } + + /** + * {@inheritdoc} + */ + public function users_to_query() + { + $actor_id = (int) $this->get_data('actor_id'); + + return ($actor_id) ? array($actor_id) : array(); + } + + /** + * {@inheritdoc} + */ + public function get_avatar() + { + $actor_id = (int) $this->get_data('actor_id'); + + return ($actor_id) ? $this->user_loader->get_avatar($actor_id, false, true) : ''; + } +} diff --git a/notification/type/contribution.php b/notification/type/contribution.php new file mode 100644 index 000000000..3faa13c45 --- /dev/null +++ b/notification/type/contribution.php @@ -0,0 +1,36 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\titania\notification\type; + +/** +* A new revision of a subscribed contribution was released. +*/ +class contribution extends base +{ + /** + * {@inheritdoc} + */ + static public $notification_option = array( + 'lang' => 'NOTIFICATION_TYPE_TITANIA_CONTRIBUTION', + 'group' => 'NOTIFICATION_GROUP_TITANIA', + ); + + /** + * {@inheritdoc} + */ + public function get_type() + { + return 'phpbb.titania.notification.type.contribution'; + } +} diff --git a/notification/type/posted.php b/notification/type/posted.php new file mode 100644 index 000000000..75d3cc23a --- /dev/null +++ b/notification/type/posted.php @@ -0,0 +1,53 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\titania\notification\type; + +/** +* New topics and replies in subscribed topics and support areas. +*/ +class posted extends base +{ + /** + * {@inheritdoc} + */ + static public $notification_option = array( + 'lang' => 'NOTIFICATION_TYPE_TITANIA_POSTED', + 'group' => 'NOTIFICATION_GROUP_TITANIA', + ); + + /** + * {@inheritdoc} + */ + public function get_type() + { + return 'phpbb.titania.notification.type.posted'; + } + + /** + * {@inheritdoc} + * + * The poster's name is resolved at display time through the user loader, + * like core's post notification does. + */ + public function get_title() + { + $params = $this->get_data('lang_params'); + $username = $this->user_loader->get_username((int) $this->get_data('actor_id'), 'no_profile'); + + return $this->language->lang_array( + $this->get_data('lang_key'), + array_merge(array($username), (is_array($params)) ? $params : array()) + ); + } +} diff --git a/notification/type/queue.php b/notification/type/queue.php new file mode 100644 index 000000000..ff1416f98 --- /dev/null +++ b/notification/type/queue.php @@ -0,0 +1,59 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\titania\notification\type; + +/** +* A new item entered a watched validation queue. +*/ +class queue extends base +{ + /** @var \phpbb\titania\contribution\type\collection */ + protected $type_collection; + + /** + * {@inheritdoc} + */ + static public $notification_option = array( + 'lang' => 'NOTIFICATION_TYPE_TITANIA_QUEUE', + 'group' => 'NOTIFICATION_GROUP_TITANIA', + ); + + /** + * Set the contribution type collection. + * + * @param \phpbb\titania\contribution\type\collection $type_collection + */ + public function set_type_collection(\phpbb\titania\contribution\type\collection $type_collection) + { + $this->type_collection = $type_collection; + } + + /** + * {@inheritdoc} + */ + public function get_type() + { + return 'phpbb.titania.notification.type.queue'; + } + + /** + * {@inheritdoc} + * + * Only users who can view at least one validation queue see the option. + */ + public function is_available() + { + return count($this->type_collection->find_authed('view')) > 0; + } +} diff --git a/notification/type/queue_move.php b/notification/type/queue_move.php new file mode 100644 index 000000000..e98591d24 --- /dev/null +++ b/notification/type/queue_move.php @@ -0,0 +1,41 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\titania\notification\type; + +/** +* A queue item moved to a watched queue category. +* +* A separate type from queue only because both events concern the same queue +* item and notifications deduplicate per type and item id; it shares the queue +* type's UCP option and preferences. +*/ +class queue_move extends queue +{ + /** + * {@inheritdoc} + */ + static public $notification_option = array( + 'id' => 'phpbb.titania.notification.type.queue', + 'lang' => 'NOTIFICATION_TYPE_TITANIA_QUEUE', + 'group' => 'NOTIFICATION_GROUP_TITANIA', + ); + + /** + * {@inheritdoc} + */ + public function get_type() + { + return 'phpbb.titania.notification.type.queue_move'; + } +} diff --git a/posting.php b/posting.php index 2c5f32988..ce70f6698 100644 --- a/posting.php +++ b/posting.php @@ -48,6 +48,9 @@ class posting /** @var \phpbb\titania\subscriptions */ protected $subscriptions; + /** @var \phpbb\path_helper */ + protected $path_helper; + /** @var \phpbb\titania\attachment\operator */ protected $attachments; @@ -76,9 +79,10 @@ class posting * @param message $message * @param access $access * @param subscriptions $subscriptions + * @param \phpbb\path_helper $path_helper * @param \phpbb\titania\attachment\operator $attachments */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, \phpbb\request\request_interface $request, \phpbb\template\template $template, controller\helper $controller_helper, message $message, access $access, subscriptions $subscriptions, \phpbb\titania\attachment\operator $attachments) + public function __construct(\phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, \phpbb\request\request_interface $request, \phpbb\template\template $template, controller\helper $controller_helper, message $message, access $access, subscriptions $subscriptions, \phpbb\path_helper $path_helper, \phpbb\titania\attachment\operator $attachments) { $this->auth = $auth; $this->db = $db; @@ -89,6 +93,7 @@ public function __construct(\phpbb\auth\auth $auth, \phpbb\db\driver\driver_inte $this->message = $message; $this->access = $access; $this->subscriptions = $subscriptions; + $this->path_helper = $path_helper; $this->attachments = $attachments; } @@ -1259,16 +1264,18 @@ protected function send_notifications(\titania_post $post, $mode) $email_vars = array( 'NAME' => htmlspecialchars_decode($post->topic->topic_subject), ); + $lang_params = array(); if ($is_support_topic) { $email_vars['CONTRIB_NAME'] = $this->contrib->contrib_name; + $lang_params[] = $this->contrib->contrib_name; } if ($mode == 'reply') { - $object_type = array(ext::TITANIA_TOPIC); - $object_id = array($post->topic_id); + $watch = array(array(ext::TITANIA_TOPIC, $post->topic_id)); + $lang_key = 'NOTIFICATION_TITANIA_REPLY'; $topic_params = array( 'view' => 'unread', '#' => 'unread', @@ -1277,26 +1284,32 @@ protected function send_notifications(\titania_post $post, $mode) if ($is_support_topic) { // Support topic reply - $object_id[] = $post->topic->parent_id; - $object_type[] = ext::TITANIA_SUPPORT; - $template .= '_contrib'; + $watch[] = array(ext::TITANIA_SUPPORT, $post->topic->parent_id); + $template .= '_contrib'; + $lang_key = 'NOTIFICATION_TITANIA_REPLY_CONTRIB'; } } else { - $object_type = $post->post_type; - $object_id = $post->topic->parent_id; - $template .= ($is_support_topic) ? '_forum_contrib' : '_forum'; + $watch = array(array($post->post_type, $post->topic->parent_id)); + $template .= ($is_support_topic) ? '_forum_contrib' : '_forum'; + $lang_key = ($is_support_topic) ? 'NOTIFICATION_TITANIA_TOPIC_CONTRIB' : 'NOTIFICATION_TITANIA_TOPIC'; } $email_vars['U_VIEW'] = $post->topic->get_url(false, $topic_params); - $this->subscriptions->send_notifications( - $object_type, - $object_id, - $template, - $email_vars, - $post->post_user_id - ); + $this->subscriptions->send_notifications('posted', array( + 'item_id' => $post->post_id, + 'item_parent_id' => $post->topic_id, + 'watch' => $watch, + 'exclude_user' => $post->post_user_id, + 'lang_key' => $lang_key, + 'lang_params' => $lang_params, + 'reference' => $post->topic->topic_subject, + 'url' => $email_vars['U_VIEW'], + 'email_template' => $template, + 'email_vars' => $email_vars, + 'actor_id' => $post->post_user_id, + )); } /** diff --git a/subscriptions.php b/subscriptions.php index c0b3ec3be..9b7213afc 100644 --- a/subscriptions.php +++ b/subscriptions.php @@ -18,58 +18,50 @@ class subscriptions /** @var \phpbb\db\driver\driver_interface */ protected $db; - /** @var \phpbb\config\config */ - protected $config; - /** @var \phpbb\request\request_interface */ protected $request; + /** @var \phpbb\template\template */ + protected $template; + /** @var \phpbb\user */ protected $user; /** @var \phpbb\path_helper */ protected $path_helper; - /** @var string */ - protected $users_table; + /** @var \phpbb\notification\manager */ + protected $notification_manager; /** @var string */ protected $watch_table; - /** @var string */ - protected $phpbb_root_path; - - /** @var string */ - protected $php_ext; - + /** + * The historical delivery type stored in watch_type. Every row carries + * EMAIL; delivery preferences now live in the notification system, so the + * column only distinguishes subscription rows, not how they are delivered. + */ const EMAIL = 1; - const WATCH = 2; /** * Constructor * * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\config\config $config * @param \phpbb\request\request_interface $request * @param \phpbb\template\template $template * @param \phpbb\user $user * @param \phpbb\path_helper $path_helper - * @param string $users_table - * @param string $phpbb_root_path - * @param string $php_ext + * @param \phpbb\notification\manager $notification_manager */ - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\request\request_interface $request, \phpbb\template\template $template, \phpbb\user $user, \phpbb\path_helper $path_helper, $users_table, $phpbb_root_path, $php_ext) + public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\request\request_interface $request, \phpbb\template\template $template, \phpbb\user $user, \phpbb\path_helper $path_helper, \phpbb\notification\manager $notification_manager) { $this->db = $db; - $this->config = $config; $this->request = $request; $this->template = $template; $this->user = $user; $this->path_helper = $path_helper; - $this->users_table = $users_table; + $this->notification_manager = $notification_manager; $this->watch_table = TITANIA_WATCH_TABLE; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; } /** @@ -201,125 +193,36 @@ public function unsubscribe($object_type, $object_id, $user_id = false) } /** - * Send Notifications - * - * Using this function: - * Call this function when you know the Object type, object id, and the email - * template name. - * Sample usage: - * - * - * - * $object_type = SOME_OBJECT_CONSTANT_TYPE; - * $obhect)id = 242974; + * Send subscription notifications through the phpBB notification system. * - * titania_subscriptions::send_notifications($object_type, $object_id, 'mod_subscribe', array( - * 'OBJECT_NAME' => 'Some MOD', - * )); - * - * - * - * The vars parameter will be used in the messanger assign vars, which will act - * as the common vars when sending out the notifications. Data such as the MOD's - * or Style's name should go here, what action was taken, etc. The usernaeme and - * emails of the recepiants will be personalised by the function. Ensure the - * email template has the {USERNAME} var present. - * - * @param $exclude_user User_id of the one who posted the item to exclude them from the sending + * Watchers of the given watch pairs receive the notification through the + * delivery methods they enabled in the UCP (board and/or email); the email + * method renders the same Titania email templates the legacy dispatcher + * used, with the same variables plus USERNAME added by the core. * + * @param string $type Titania notification type suffix + * (posted|contribution|queue|queue_move|attention) + * @param array $type_data Notification data: + * 'item_id' int the notified item (post, revision, queue, attention id) + * 'item_parent_id' int its parent (optional) + * 'watch' array of array(watch_object_type, watch_object_id) + * pairs selecting the recipients + * 'exclude_user' int user to exclude, normally the acting user (optional) + * 'lang_key' string language key for the board notification title + * 'lang_params' array parameters for the language key (optional) + * 'url' string url the notification links to + * 'email_template' string Titania email template name + * 'email_vars' array variables for the email template (optional) + * 'actor_id' int user shown as the notification's actor (optional) */ - public function send_notifications($object_type, $object_id, $email_tpl, $vars, $exclude_user = false) + public function send_notifications($type, array $type_data) { - $sql = 'SELECT w.watch_user_id, w.watch_type, u.user_id, u.username, u.user_email, u.user_lang - FROM ' . $this->watch_table . ' w, ' . $this->users_table . ' u - WHERE w.watch_user_id = u.user_id '; - - if (is_array($object_type) || is_array($object_id)) - { - // Both needs to be arrays if one is and they need to have the same number of elements. - if (!is_array($object_type) || !is_array($object_id) || sizeof($object_type) != sizeof($object_id)) - { - return; - } - - $sql_objects = ''; - foreach ($object_type as $key => $value) - { - $sql_objects .= (($sql_objects == '') ? '' : ' OR ') . '(w.watch_object_type = ' . (int) $value . ' - AND w.watch_object_id = ' . (int) $object_id[$key] . ')'; - } - $sql .= 'AND (' . $sql_objects . ')'; - - unset($sql_objects); - } - else - { - $sql .= 'AND w.watch_object_type = ' . (int) $object_type . ' - AND w.watch_object_id = ' . (int) $object_id; - } - $sql .= ($exclude_user) ? ' AND w.watch_user_id <> ' . (int) $exclude_user : ''; - - $result = $this->db->sql_query($sql); - - // Throw everything here - $user_data = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - // Use user_id for the keys to not send duplicates. - $user_data[$row['user_id']] = array( - 'username' => $row['username'], - 'user_email' => $row['user_email'], - 'user_lang' => $row['user_lang'], - 'watch_type' => $row['watch_type'], - ); - } - $this->db->sql_freeresult($result); - - // No one subscribed? We're done. - if (empty($user_data)) - { - return; - } - $messenger = null; - - // Send to each user - // Add a new case statment for each subscription type - foreach ($user_data as $data) + // A stored notification url must never carry a session id + if (!empty($type_data['url'])) { - /* - * Switch between the types. - * ------------------------------------------ - * When adding a type, the final message will - * be stored in $message, and the subject is - * stored in $vars['SUBJECT']. - */ - switch($data['watch_type']) - { - case self::EMAIL: - - if ($messenger === null) - { - // Only make the object if we need it - if (!class_exists('\messenger')) - { - require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext); - } - $messenger = new \messenger; - } - - $messenger->anti_abuse_headers($this->config, $this->user); - $messenger->template('@phpbb_titania/' . $email_tpl, $data['user_lang']); - $messenger->to($data['user_email'], $data['username']); - $messenger->assign_vars(array_merge($vars, array( - 'USERNAME' => $data['username'], - ))); - - $messenger->send(); - $messenger->save_queue(); - break; - } + $type_data['url'] = $this->path_helper->strip_url_params($type_data['url'], 'sid'); } - return; + $this->notification_manager->add_notifications('phpbb.titania.notification.type.' . $type, $type_data); } }