Skip to content

Commit f6ad9a3

Browse files
authored
Merge pull request #66 from iMattPro/progressive-web-app
Progressive Web App support
2 parents 329a938 + 2b77944 commit f6ad9a3

11 files changed

Lines changed: 486 additions & 14 deletions

File tree

config/routing.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
phpbb_webpushnotifications_ucp_routing:
22
resource: wpn_ucp.yml
33
prefix: /user
4+
5+
phpbb_webpushnotifications_manifest_controller:
6+
path: /manifest
7+
defaults: { _controller: phpbb.wpn.controller.manifest:handle }

config/services.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ services:
1212
phpbb.wpn.listener:
1313
class: phpbb\webpushnotifications\event\listener
1414
arguments:
15+
- '@config'
1516
- '@controller.helper'
17+
- '@upload_imagesize'
1618
- '@phpbb.wpn.form_helper'
1719
- '@language'
1820
- '@template'
1921
- '@notification_manager'
22+
- '%core.root_path%'
2023
tags:
2124
- { name: event.listener }
2225

@@ -52,3 +55,10 @@ services:
5255
- '%tables.phpbb.wpn.notification_push%'
5356
- '%tables.phpbb.wpn.push_subscriptions%'
5457

58+
phpbb.wpn.controller.manifest:
59+
class: phpbb\webpushnotifications\controller\manifest
60+
arguments:
61+
- '@config'
62+
- '@language'
63+
- '@path_helper'
64+
- '@user'

controller/manifest.php

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
/**
3+
*
4+
* phpBB Browser Push Notifications. An extension for the phpBB Forum Software package.
5+
*
6+
* @copyright (c) 2024, phpBB Limited <https://www.phpbb.com>
7+
* @license GNU General Public License, version 2 (GPL-2.0)
8+
*
9+
*/
10+
11+
namespace phpbb\webpushnotifications\controller;
12+
13+
use phpbb\config\config;
14+
use phpbb\exception\http_exception;
15+
use phpbb\language\language;
16+
use phpbb\path_helper;
17+
use phpbb\user;
18+
use Symfony\Component\HttpFoundation\JsonResponse;
19+
use Symfony\Component\HttpFoundation\Response;
20+
21+
class manifest
22+
{
23+
/** @var config */
24+
protected $config;
25+
26+
/** @var language */
27+
protected $language;
28+
29+
/** @var path_helper */
30+
protected $path_helper;
31+
32+
/** @var user */
33+
protected $user;
34+
35+
/**
36+
* Constructor for webpush controller
37+
*
38+
* @param config $config
39+
* @param path_helper $path_helper
40+
* @param language $language
41+
* @param user $user
42+
*/
43+
public function __construct(config $config, language $language, path_helper $path_helper, user $user)
44+
{
45+
$this->config = $config;
46+
$this->path_helper = $path_helper;
47+
$this->language = $language;
48+
$this->user = $user;
49+
}
50+
51+
/**
52+
* Handle creation of a manifest json file for progressive web-app support
53+
*
54+
* @return JsonResponse
55+
*/
56+
public function handle(): JsonResponse
57+
{
58+
if ($this->user->data['is_bot'] || $this->user->data['user_type'] == USER_INACTIVE)
59+
{
60+
throw new http_exception(Response::HTTP_FORBIDDEN, 'Forbidden');
61+
}
62+
63+
$board_path = $this->config['force_server_vars'] ? $this->config['script_path'] : $this->path_helper->get_web_root_path();
64+
65+
$manifest = [
66+
'name' => $this->config['sitename'],
67+
'short_name' => $this->config['pwa_short_name'] ?: substr($this->config['sitename'], 0, 12),
68+
'display' => 'standalone',
69+
'orientation' => 'portrait',
70+
'dir' => $this->language->lang('DIRECTION'),
71+
'start_url' => $board_path,
72+
'scope' => $board_path,
73+
];
74+
75+
if (!empty($this->config['pwa_icon_small']) && !empty($this->config['pwa_icon_large']))
76+
{
77+
$manifest['icons'] = [
78+
[
79+
'src' => $this->config['icons_path'] . '/' . $this->config['pwa_icon_small'],
80+
'sizes' => '192x192',
81+
'type' => 'image/png'
82+
],
83+
[
84+
'src' => $this->config['icons_path'] . '/' . $this->config['pwa_icon_large'],
85+
'sizes' => '512x512',
86+
'type' => 'image/png'
87+
]
88+
];
89+
}
90+
91+
return new JsonResponse($manifest);
92+
}
93+
}

event/listener.php

Lines changed: 110 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,33 @@
1313
/**
1414
* @ignore
1515
*/
16-
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16+
17+
use FastImageSize\FastImageSize;
18+
use phpbb\config\config;
1719
use phpbb\controller\helper as controller_helper;
18-
use phpbb\webpushnotifications\form\form_helper;
1920
use phpbb\language\language;
2021
use phpbb\notification\manager;
2122
use phpbb\template\template;
23+
use phpbb\webpushnotifications\form\form_helper;
24+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
2225

2326
/**
2427
* Event listener
2528
*/
2629
class listener implements EventSubscriberInterface
2730
{
28-
public static function getSubscribedEvents()
29-
{
30-
return [
31-
'core.ucp_display_module_before' => 'load_language',
32-
'core.acp_main_notice' => 'compatibility_notice',
33-
'core.page_header_after' => 'load_template_data',
34-
];
35-
}
31+
/** @var config */
32+
protected $config;
3633

3734
/* @var controller_helper */
3835
protected $controller_helper;
3936

4037
/* @var form_helper */
4138
protected $form_helper;
4239

40+
/** @var FastImageSize */
41+
protected $imagesize;
42+
4343
/* @var language */
4444
protected $language;
4545

@@ -49,22 +49,42 @@ public static function getSubscribedEvents()
4949
/* @var manager */
5050
protected $phpbb_notifications;
5151

52+
/** @var string */
53+
protected $root_path;
54+
5255
/**
5356
* Constructor
5457
*
58+
* @param config $config
5559
* @param controller_helper $controller_helper Controller helper object
60+
* @param FastImageSize $imagesize
5661
* @param form_helper $form_helper Form helper object
5762
* @param language $language Language object
5863
* @param template $template Template object
5964
* @param manager $phpbb_notifications Notifications manager object
65+
* @param $root_path
6066
*/
61-
public function __construct(controller_helper $controller_helper, form_helper $form_helper, language $language, template $template, manager $phpbb_notifications)
67+
public function __construct(config $config, controller_helper $controller_helper, FastImageSize $imagesize, form_helper $form_helper, language $language, template $template, manager $phpbb_notifications, $root_path)
6268
{
69+
$this->config = $config;
6370
$this->controller_helper = $controller_helper;
71+
$this->imagesize = $imagesize;
6472
$this->form_helper = $form_helper;
6573
$this->language = $language;
6674
$this->template = $template;
6775
$this->phpbb_notifications = $phpbb_notifications;
76+
$this->root_path = $root_path;
77+
}
78+
79+
public static function getSubscribedEvents()
80+
{
81+
return [
82+
'core.ucp_display_module_before' => 'load_language',
83+
'core.acp_main_notice' => 'compatibility_notice',
84+
'core.page_header_after' => 'load_template_data',
85+
'core.acp_board_config_edit_add' => 'acp_pwa_options',
86+
'core.validate_config_variable' => 'validate_pwa_options',
87+
];
6888
}
6989

7090
/**
@@ -102,4 +122,83 @@ public function compatibility_notice()
102122
{
103123
$this->template->assign_var('S_WPN_COMPATIBILITY_NOTICE', phpbb_version_compare(PHPBB_VERSION, '4.0.0-dev', '>='));
104124
}
125+
126+
/**
127+
* Progressive web app options for the ACP
128+
*
129+
* @param \phpbb\event\data $event
130+
* @return void
131+
*/
132+
public function acp_pwa_options($event)
133+
{
134+
if ($event['mode'] === 'settings' && array_key_exists('legend4', $event['display_vars']['vars']))
135+
{
136+
$this->language->add_lang('webpushnotifications_common_acp', 'phpbb/webpushnotifications');
137+
138+
$my_config_vars = [
139+
'legend_pwa_settings'=> 'PWA_SETTINGS',
140+
'pwa_short_name' => ['lang' => 'PWA_SHORT_NAME', 'validate' => 'string', 'type' => 'text:40:12', 'explain' => true],
141+
'pwa_icon_small' => ['lang' => 'PWA_ICON_SMALL', 'validate' => 'pwa_options', 'type' => 'custom', 'function' => [$this, 'pwa_icon_name'], 'explain' => true],
142+
'pwa_icon_large' => ['lang' => 'PWA_ICON_LARGE', 'validate' => 'pwa_options', 'type' => 'custom', 'function' => [$this, 'pwa_icon_name'], 'explain' => true],
143+
];
144+
145+
$event->update_subarray('display_vars', 'vars', phpbb_insert_config_array($event['display_vars']['vars'], $my_config_vars, ['before' => 'legend4']));
146+
}
147+
}
148+
149+
/**
150+
* Return HTML for PWA icon name settings
151+
*
152+
* @param string $value Value of config
153+
* @param string $key Name of config
154+
* @return string
155+
*/
156+
public function pwa_icon_name($value, $key)
157+
{
158+
return $this->config['icons_path'] . '/<input id="' . $key . '" type="text" size="40" maxlength="255" name="config[' . $key . ']" value="' . $value . '">';
159+
}
160+
161+
/**
162+
* Validate PWA options
163+
*
164+
* @param \phpbb\event\data $event
165+
* @return void
166+
*/
167+
public function validate_pwa_options($event)
168+
{
169+
if ($event['config_definition']['validate'] !== 'pwa_options' || empty($event['cfg_array']['pwa_icon_small']) || empty($event['cfg_array']['pwa_icon_large']))
170+
{
171+
return;
172+
}
173+
174+
$value = $event['cfg_array'][$event['config_name']];
175+
$error = $event['error'];
176+
177+
$image = $this->root_path . $this->config['icons_path'] . '/' . $value;
178+
if (!file_exists($image))
179+
{
180+
$error[] = $this->language->lang('PWA_IMAGE_NOT_FOUND', $value);
181+
}
182+
183+
$image_info = $this->imagesize->getImageSize($image);
184+
if ($image_info !== false)
185+
{
186+
if (($event['config_name'] === 'pwa_icon_small' && $image_info['width'] !== 192 && $image_info['height'] !== 192) ||
187+
($event['config_name'] === 'pwa_icon_large' && $image_info['width'] !== 512 && $image_info['height'] !== 512))
188+
{
189+
$error[] = $this->language->lang('PWA_ICON_SIZE_INVALID', $value);
190+
}
191+
192+
if ($image_info['type'] !== IMAGETYPE_PNG)
193+
{
194+
$error[] = $this->language->lang('PWA_ICON_MIME_INVALID', $value);
195+
}
196+
}
197+
else
198+
{
199+
$error[] = $this->language->lang('PWA_IMAGE_INVALID', $value);
200+
}
201+
202+
$event['error'] = $error;
203+
}
105204
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
/**
3+
*
4+
* phpBB Browser Push Notifications. An extension for the phpBB Forum Software package.
5+
*
6+
* @copyright (c) 2024, phpBB Limited <https://www.phpbb.com>
7+
* @license GNU General Public License, version 2 (GPL-2.0)
8+
*
9+
*/
10+
11+
/**
12+
* DO NOT CHANGE
13+
*/
14+
if (!defined('IN_PHPBB'))
15+
{
16+
exit;
17+
}
18+
19+
if (empty($lang) || !is_array($lang))
20+
{
21+
$lang = [];
22+
}
23+
24+
// DEVELOPERS PLEASE NOTE
25+
//
26+
// All language files should use UTF-8 as their encoding and the files must not contain a BOM.
27+
//
28+
// Placeholders can now contain order information, e.g. instead of
29+
// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows
30+
// translators to re-order the output of data while ensuring it remains correct
31+
//
32+
// You do not need this where single placeholders are used, e.g. 'Message %d' is fine
33+
// equally where a string contains only two placeholders which are used to wrap text
34+
// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
35+
//
36+
// Some characters you may want to copy&paste:
37+
// ’ » “ ” …
38+
//
39+
40+
$lang = array_merge($lang, [
41+
'PWA_SETTINGS' => 'Progressive web application options',
42+
'PWA_SHORT_NAME' => 'Short site name',
43+
'PWA_SHORT_NAME_EXPLAIN' => 'Your site name in 12 characters or less, which may be used as a label for an icon on a mobile device’s home screen.',
44+
'PWA_ICON_SMALL' => 'Small mobile device icon',
45+
'PWA_ICON_SMALL_EXPLAIN' => 'File name of a 192px x 192px PNG image. This file must be uploaded to your board’s <samp>icons</samp> directory.',
46+
'PWA_ICON_LARGE' => 'Large mobile device icon',
47+
'PWA_ICON_LARGE_EXPLAIN' => 'File name of a 512px x 512px PNG image. This file must be uploaded to your board’s <samp>icons</samp> directory.',
48+
'PWA_ICON_SIZE_INVALID' => '%s does not have the correct image dimensions.',
49+
'PWA_ICON_MIME_INVALID' => '%s must be a PNG image file.',
50+
'PWA_IMAGE_INVALID' => '%s does not appear to be a valid image file.',
51+
'PWA_IMAGE_NOT_FOUND' => '%s could not be found.',
52+
]);

language/en/webpushnotifications_module_acp.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
//
3939

4040
$lang = array_merge($lang, [
41-
'ACP_WEBPUSH_SETTINGS_EXPLAIN' => 'Here you can enable Web Push for board notifications. Web Push is a protocol for the real-time delivery of events to user agents, commonly referred to as push messages. It is compatible with the majority of modern browsers on both desktop and mobile devices. Users can opt to receive Web Push alerts in their browser by subscribing and enabling their preferred notifications in the UCP.',
41+
'ACP_WEBPUSH_SETTINGS_EXPLAIN' => 'Here you can enable Web Push for board notifications. Web Push is a protocol for the real-time delivery of events to user agents, commonly referred to as push messages. It is compatible with the majority of modern browsers on both desktop and mobile devices. Users can opt to receive Web Push alerts in their browser by subscribing and enabling their preferred notifications in the UCP.<br><br>To enable push notifications on Apple mobile devices, your site needs to function as a Progressive Web Application (PWA). This requires users to add your site to their device’s home screen. For an improved user experience, you can find additional PWA settings under <strong>Board settings</strong>, where you can configure an optional app name and app icons for how your site will appear on users’ home screens.',
4242
'WEBPUSH_ENABLE' => 'Enable Web Push',
4343
'WEBPUSH_ENABLE_EXPLAIN' => 'Allow users to receive notifications in their browser or device via Web Push. To utilize Web Push, you must input or generate valid VAPID identification keys.',
4444
'WEBPUSH_GENERATE_VAPID_KEYS' => 'Generate Identification keys',

0 commit comments

Comments
 (0)