diff --git a/config/services.yml b/config/services.yml
index 4ec48f3..07cd894 100644
--- a/config/services.yml
+++ b/config/services.yml
@@ -30,7 +30,6 @@ services:
arguments:
- '@config'
- '@dbal.conn'
- - '@language'
- '@log'
- '@user_loader'
- '@user'
@@ -49,8 +48,11 @@ services:
- '@controller.helper'
- '@dbal.conn'
- '@phpbb.wpn.form_helper'
+ - '@language'
+ - '@notification_manager'
- '@path_helper'
- '@request'
+ - '@user_loader'
- '@user'
- '@template.twig.environment'
- '%tables.phpbb.wpn.notification_push%'
diff --git a/notification/method/webpush.php b/notification/method/webpush.php
index 824bfc7..fc7f0c3 100644
--- a/notification/method/webpush.php
+++ b/notification/method/webpush.php
@@ -14,7 +14,6 @@
use phpbb\config\config;
use phpbb\controller\helper;
use phpbb\db\driver\driver_interface;
-use phpbb\language\language;
use phpbb\log\log_interface;
use phpbb\notification\method\messenger_base;
use phpbb\notification\type\type_interface;
@@ -36,9 +35,6 @@ class webpush extends messenger_base implements extended_method_interface
/** @var driver_interface */
protected $db;
- /** @var language */
- protected $language;
-
/** @var log_interface */
protected $log;
@@ -65,7 +61,6 @@ class webpush extends messenger_base implements extended_method_interface
*
* @param config $config
* @param driver_interface $db
- * @param language $language
* @param log_interface $log
* @param user_loader $user_loader
* @param user $user
@@ -75,14 +70,13 @@ class webpush extends messenger_base implements extended_method_interface
* @param string $notification_webpush_table
* @param string $push_subscriptions_table
*/
- public function __construct(config $config, driver_interface $db, language $language, log_interface $log, user_loader $user_loader, user $user, path_helper $path_helper,
+ public function __construct(config $config, driver_interface $db, log_interface $log, user_loader $user_loader, user $user, path_helper $path_helper,
string $phpbb_root_path, string $php_ext, string $notification_webpush_table, string $push_subscriptions_table)
{
parent::__construct($user_loader, $phpbb_root_path, $php_ext);
$this->config = $config;
$this->db = $db;
- $this->language = $language;
$this->log = $log;
$this->user = $user;
$this->path_helper = $path_helper;
@@ -145,29 +139,15 @@ public function notify()
{
$insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, $this->notification_webpush_table);
- // Load all users data we want to notify
- $notify_users = $this->load_recipients_data();
-
/** @var type_interface $notification */
foreach ($this->queue as $notification)
{
$data = $notification->get_insert_array();
-
- // Change notification language if needed only
- $recipient_data = $this->user_loader->get_user($notification->user_id);
- if ($this->language->get_used_language() !== $recipient_data['user_lang'])
- {
- $this->language->set_user_language($recipient_data['user_lang'], true);
- }
-
$data += [
- 'push_data' => json_encode([
- 'heading' => $this->config['sitename'],
- 'title' => strip_tags($notification->get_title()),
- 'text' => strip_tags($notification->get_reference()),
- 'url' => htmlspecialchars_decode($notification->get_url()),
- 'avatar' => $this->prepare_avatar($notification->get_avatar()),
- ]),
+ 'push_data' => json_encode(array_merge(
+ $data,
+ ['notification_type_name' => $notification->get_type()]
+ )),
'notification_time' => time(),
'push_token' => hash('sha256', random_bytes(32))
];
@@ -178,13 +158,7 @@ public function notify()
$insert_buffer->flush();
- // Restore current user's language if needed only
- if ($this->language->get_used_language() !== $this->user->data['user_lang'])
- {
- $this->language->set_user_language($this->user->data['user_lang'], true);
- }
-
- $this->notify_using_webpush($notify_users);
+ $this->notify_using_webpush();
return false;
}
@@ -192,16 +166,33 @@ public function notify()
/**
* Notify using Web Push
*
- * @param array $notify_users Array of user ids to notify
* @return void
*/
- protected function notify_using_webpush($notify_users = []): void
+ protected function notify_using_webpush(): void
{
if (empty($this->queue))
{
return;
}
+ // Load all users we want to notify
+ $user_ids = [];
+ foreach ($this->queue as $notification)
+ {
+ $user_ids[] = $notification->user_id;
+ }
+
+ // Do not send push notifications to banned users
+ if (!function_exists('phpbb_get_banned_user_ids'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+ $banned_users = phpbb_get_banned_user_ids($user_ids);
+
+ // Load all the users we need
+ $notify_users = array_diff($user_ids, $banned_users);
+ $this->user_loader->load_users($notify_users, [USER_IGNORE]);
+
// Get subscriptions for users
$user_subscription_map = $this->get_user_subscription_map($notify_users);
@@ -361,6 +352,14 @@ public static function clean_data(array $data): array
return array_intersect_key($data, $row);
}
+ /**
+ * Get template data for the UCP
+ *
+ * @param helper $controller_helper
+ * @param form_helper $form_helper
+ *
+ * @return array
+ */
public function get_ucp_template_data(helper $controller_helper, form_helper $form_helper): array
{
$subscription_map = $this->get_user_subscription_map([$this->user->id()]);
@@ -461,46 +460,6 @@ protected function clean_expired_subscriptions(array $user_subscription_map, arr
$this->remove_subscriptions($remove_subscriptions);
}
- /**
- * Takes an avatar string (usually in full html format already) and extracts the url.
- * If the avatar url is a relative path, it's converted to an absolute path.
- *
- * Converts:
- *
- * or
- * into https://myboard.url/path/to/avatar=123456789.gif
- *
- * @param string $avatar
- * @return array 'src' => Absolute path to avatar image
- */
- protected function prepare_avatar($avatar): array
- {
- $pattern = '/src=["\']?([^"\'>]+)["\']?/';
-
- preg_match_all($pattern, $avatar, $matches);
-
- $path = !empty($matches[1]) ? end($matches[1]) : $avatar;
-
- return ['src' => preg_replace('#^' . preg_quote($this->path_helper->get_web_root_path(), '#') . '#', $this->get_board_url(), $path, 1)];
- }
-
- /**
- * Returns the board url (and caches it in the function)
- *
- * @return string the generated board url
- */
- protected function get_board_url()
- {
- static $board_url;
-
- if (empty($board_url))
- {
- $board_url = generate_board_url() . '/';
- }
-
- return $board_url;
- }
-
/**
* Set web push padding for endpoint
*
@@ -523,31 +482,4 @@ protected function set_endpoint_padding(\Minishlink\WebPush\WebPush $web_push, s
}
}
}
-
- /**
- * Load all users data to send notifications
- *
- * @return array Array of user ids to notify
- */
- protected function load_recipients_data(): array
- {
- $notify_users = $user_ids = [];
- foreach ($this->queue as $notification)
- {
- $user_ids[] = $notification->user_id;
- }
-
- // Do not send push notifications to banned users
- if (!function_exists('phpbb_get_banned_user_ids'))
- {
- include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
- }
- $banned_users = phpbb_get_banned_user_ids($user_ids);
-
- // Load all the users we need
- $notify_users = array_diff($user_ids, $banned_users);
- $this->user_loader->load_users($notify_users, [USER_IGNORE]);
-
- return $notify_users;
- }
}
diff --git a/tests/event/listener_test.php b/tests/event/listener_test.php
index a26ef00..ce75a8d 100644
--- a/tests/event/listener_test.php
+++ b/tests/event/listener_test.php
@@ -108,7 +108,6 @@ protected function setUp(): void
$this->notification_method_webpush = new \phpbb\webpushnotifications\notification\method\webpush(
$this->config,
$db,
- $this->language,
new \phpbb\log\dummy(),
$user_loader,
$this->user,
diff --git a/tests/notification/notification_method_webpush_test.php b/tests/notification/notification_method_webpush_test.php
index 6829ffe..a60ee31 100644
--- a/tests/notification/notification_method_webpush_test.php
+++ b/tests/notification/notification_method_webpush_test.php
@@ -171,7 +171,6 @@ protected function setUp(): void
$this->notification_method_webpush = new webpush(
$phpbb_container->get('config'),
$phpbb_container->get('dbal.conn'),
- $phpbb_container->get('language'),
$phpbb_container->get('log'),
$phpbb_container->get('user_loader'),
$phpbb_container->get('user'),
diff --git a/ucp/controller/webpush.php b/ucp/controller/webpush.php
index ce79538..08b3961 100644
--- a/ucp/controller/webpush.php
+++ b/ucp/controller/webpush.php
@@ -14,12 +14,15 @@
use phpbb\controller\helper as controller_helper;
use phpbb\db\driver\driver_interface;
use phpbb\exception\http_exception;
+use phpbb\language\language;
+use phpbb\notification\manager;
use phpbb\webpushnotifications\form\form_helper;
use phpbb\webpushnotifications\json\sanitizer as json_sanitizer;
use phpbb\path_helper;
use phpbb\request\request_interface;
use phpbb\symfony_request;
use phpbb\user;
+use phpbb\user_loader;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
@@ -44,12 +47,21 @@ class webpush
/** @var form_helper */
protected $form_helper;
+ /** @var language */
+ protected $language;
+
+ /** @var manager */
+ protected $notification_manager;
+
/** @var path_helper */
protected $path_helper;
/** @var request_interface */
protected $request;
+ /** @var user_loader */
+ protected $user_loader;
+
/** @var user */
protected $user;
@@ -69,22 +81,28 @@ class webpush
* @param controller_helper $controller_helper
* @param driver_interface $db
* @param form_helper $form_helper
+ * @param language $language
+ * @param manager $notification_manager
* @param path_helper $path_helper
* @param request_interface $request
+ * @param user_loader $user_loader
* @param user $user
* @param Environment $template
* @param string $notification_webpush_table
* @param string $push_subscriptions_table
*/
- public function __construct(config $config, controller_helper $controller_helper, driver_interface $db, form_helper $form_helper, path_helper $path_helper,
- request_interface $request, user $user, Environment $template, string $notification_webpush_table, string $push_subscriptions_table)
+ public function __construct(config $config, controller_helper $controller_helper, driver_interface $db, form_helper $form_helper, language $language, manager $notification_manager,
+ path_helper $path_helper, request_interface $request, user_loader $user_loader, user $user, Environment $template, string $notification_webpush_table, string $push_subscriptions_table)
{
$this->config = $config;
$this->controller_helper = $controller_helper;
$this->db = $db;
$this->form_helper = $form_helper;
+ $this->language = $language;
+ $this->notification_manager = $notification_manager;
$this->path_helper = $path_helper;
$this->request = $request;
+ $this->user_loader = $user_loader;
$this->user = $user;
$this->template = $template;
$this->notification_webpush_table = $notification_webpush_table;
@@ -105,10 +123,9 @@ public function notification(): JsonResponse
$notification_data = $this->get_user_notifications();
- // Decode and return data if everything is fine; update url paths and decode message emoji
+ // Decode and return data if everything is fine
$data = json_decode($notification_data, true);
$data['url'] = isset($data['url']) ? $this->path_helper->update_web_root_path($data['url']) : '';
- $data['text'] = isset($data['text']) ? html_entity_decode($data['text'], ENT_NOQUOTES, 'UTF-8') : '';
return new JsonResponse($data);
}
@@ -143,7 +160,7 @@ private function get_user_notifications(): string
$notification_data = $this->db->sql_fetchfield('push_data');
$this->db->sql_freeresult($result);
- return $notification_data;
+ return $this->get_notification_data($notification_data);
}
/**
@@ -174,23 +191,62 @@ private function get_anonymous_notifications(): string
$push_token = $notification_row['push_token'];
// Check if passed push token is valid
- $sql = 'SELECT user_form_salt
+ $sql = 'SELECT user_form_salt, user_lang
FROM ' . USERS_TABLE . '
WHERE user_id = ' . (int) $user_id;
$result = $this->db->sql_query($sql);
- $user_form_token = $this->db->sql_fetchfield('user_form_salt');
+ $row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
+ $user_form_token = $row['user_form_salt'];
+ $user_lang = $row['user_lang'];
+
$expected_push_token = hash('sha256', $user_form_token . $push_token);
if ($expected_push_token === $token)
{
- return $notification_data;
+ if ($user_lang !== $this->language->get_used_language())
+ {
+ $this->language->set_user_language($user_lang, true);
+ }
+ return $this->get_notification_data($notification_data);
}
}
throw new http_exception(Response::HTTP_FORBIDDEN, 'NO_AUTH_OPERATION');
}
+ /**
+ * Get notification data for output from json encoded data stored in database
+ *
+ * @param string $notification_data Encoded data stored in database
+ *
+ * @return string Data for notification output with javascript
+ */
+ private function get_notification_data(string $notification_data): string
+ {
+ $row_data = json_decode($notification_data, true);
+
+ // Old notification data is pre-parsed and just needs to be returned
+ if (isset($row_data['heading']))
+ {
+ return $notification_data;
+ }
+
+ // Get notification from row_data
+ $notification = $this->notification_manager->get_item_type_class($row_data['notification_type_name'], $row_data);
+
+ // Load users for notification
+ $this->user_loader->load_users($notification->users_to_query());
+
+ return json_encode([
+ 'heading' => $this->config['sitename'],
+ 'title' => strip_tags(html_entity_decode($notification->get_title(), ENT_NOQUOTES, 'UTF-8')),
+ 'text' => strip_tags(html_entity_decode($notification->get_reference(), ENT_NOQUOTES, 'UTF-8')),
+ 'url' => htmlspecialchars_decode($notification->get_url()),
+ 'avatar' => $this->prepare_avatar($notification->get_avatar()),
+ ]);
+ }
+
/**
* Handle request to push worker javascript
*
@@ -201,7 +257,6 @@ private function get_anonymous_notifications(): string
*/
public function worker(): Response
{
- // @todo: only work for logged in users, no anonymous & bot
$content = $this->template->render('@phpbb_webpushnotifications/push_worker.js.twig', [
'U_WEBPUSH_GET_NOTIFICATION' => $this->controller_helper->route('phpbb_webpushnotifications_ucp_push_get_notification_controller'),
'ASSETS_VERSION' => $this->config['assets_version'],
@@ -219,20 +274,6 @@ public function worker(): Response
return $response;
}
- /**
- * Get template variables for subscribe type pages
- *
- * @return array
- */
- protected function get_subscribe_vars(): array
- {
- return [
- 'U_WEBPUSH_SUBSCRIBE' => $this->controller_helper->route('phpbb_webpushnotifications_ucp_push_subscribe_controller'),
- 'U_WEBPUSH_UNSUBSCRIBE' => $this->controller_helper->route('phpbb_webpushnotifications_ucp_push_unsubscribe_controller'),
- 'FORM_TOKENS' => $this->form_helper->get_form_tokens(self::FORM_TOKEN_UCP),
- ];
- }
-
/**
* Check (un)subscribe form for valid link hash
*
@@ -305,4 +346,44 @@ public function unsubscribe(symfony_request $symfony_request): JsonResponse
'form_tokens' => $this->form_helper->get_form_tokens(self::FORM_TOKEN_UCP),
]);
}
+
+ /**
+ * Takes an avatar string (usually in full html format already) and extracts the url.
+ * If the avatar url is a relative path, it's converted to an absolute path.
+ *
+ * Converts:
+ *
+ * or
+ * into https://myboard.url/path/to/avatar=123456789.gif
+ *
+ * @param string $avatar
+ * @return array 'src' => Absolute path to avatar image
+ */
+ protected function prepare_avatar($avatar): array
+ {
+ $pattern = '/src=["\']?([^"\'>]+)["\']?/';
+
+ preg_match_all($pattern, $avatar, $matches);
+
+ $path = !empty($matches[1]) ? end($matches[1]) : $avatar;
+
+ return ['src' => preg_replace('#^' . preg_quote($this->path_helper->get_web_root_path(), '#') . '#', $this->get_board_url(), $path, 1)];
+ }
+
+ /**
+ * Returns the board url (and caches it in the function)
+ *
+ * @return string the generated board url
+ */
+ protected function get_board_url()
+ {
+ static $board_url;
+
+ if (empty($board_url))
+ {
+ $board_url = generate_board_url() . '/';
+ }
+
+ return $board_url;
+ }
}