Skip to content

Commit

Permalink
Merge pull request #79 from iMattPro/updates
Browse files Browse the repository at this point in the history
Updates!
  • Loading branch information
iMattPro authored Sep 14, 2024
2 parents 674b9cb + fe74605 commit 02babec
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 42 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is the repository for the development of the phpBB Browser Push Notifications extension.

[![Build Status](https://github.com/phpbb-extensions/webpushnotifications/workflows/Tests/badge.svg)](https://github.com/phpbb-extensions/webpushnotifications/actions)
[![Build Status](https://github.com/phpbb-extensions/webpushnotifications/actions/workflows/tests.yml/badge.svg)](https://github.com/phpbb-extensions/webpushnotifications/actions)

An official phpBB extension that allows board users to receive browser-based push notifications.

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"type": "phpbb-extension",
"description": "An official phpBB extension that allows board users to receive browser-based push notifications.",
"homepage": "https://www.phpbb.com/customise/db/extension/webpushnotifications/",
"version": "1.0.0",
"version": "1.0.1-dev",
"license": "GPL-2.0-only",
"authors": [
{
Expand Down
2 changes: 1 addition & 1 deletion controller/manifest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function handle(): JsonResponse

$manifest = [
'name' => $this->config['sitename'],
'short_name' => $this->config['pwa_short_name'] ?: substr($this->config['sitename'], 0, 12),
'short_name' => $this->config['pwa_short_name'] ?: utf8_substr(preg_replace('/[^\x20-\x7E]/', '', $this->config['sitename']), 0, 12),
'display' => 'standalone',
'orientation' => 'portrait',
'dir' => $this->language->lang('DIRECTION'),
Expand Down
125 changes: 95 additions & 30 deletions event/listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ public function pwa_manifest()
$this->template->assign_vars([
'U_MANIFEST_URL' => $this->controller_helper->route('phpbb_webpushnotifications_manifest_controller'),
'U_TOUCH_ICON' => $this->config['pwa_icon_small'],
'SHORT_SITE_NAME' => $this->config['pwa_short_name'] ?: $this->get_shortname($this->config['sitename']),
]);
}

Expand All @@ -159,9 +160,9 @@ public function acp_pwa_options($event)

$my_config_vars = [
'legend_pwa_settings'=> 'PWA_SETTINGS',
'pwa_short_name' => ['lang' => 'PWA_SHORT_NAME', 'validate' => 'string', 'type' => 'text:40:12', 'explain' => true],
'pwa_icon_small' => ['lang' => 'PWA_ICON_SMALL', 'validate' => 'pwa_options', 'type' => 'custom', 'function' => [$this, 'pwa_icon_name'], 'explain' => true],
'pwa_icon_large' => ['lang' => 'PWA_ICON_LARGE', 'validate' => 'pwa_options', 'type' => 'custom', 'function' => [$this, 'pwa_icon_name'], 'explain' => true],
'pwa_short_name' => ['lang' => 'PWA_SHORT_NAME', 'validate' => 'pwa_options:string', 'type' => 'custom', 'function' => [$this, 'pwa_short_sitename'], 'explain' => true],
'pwa_icon_small' => ['lang' => 'PWA_ICON_SMALL', 'validate' => 'pwa_options:icons', 'type' => 'custom', 'function' => [$this, 'pwa_icon_name'], 'explain' => true],
'pwa_icon_large' => ['lang' => 'PWA_ICON_LARGE', 'validate' => 'pwa_options:icons', 'type' => 'custom', 'function' => [$this, 'pwa_icon_name'], 'explain' => true],
];

$event->update_subarray('display_vars', 'vars', phpbb_insert_config_array($event['display_vars']['vars'], $my_config_vars, ['before' => 'legend4']));
Expand All @@ -180,6 +181,20 @@ public function pwa_icon_name($value, $key)
return $this->config['icons_path'] . '/<input id="' . $key . '" type="text" size="40" maxlength="255" name="config[' . $key . ']" value="' . $value . '">';
}

/**
* Return HTML for PWA short site name setting
*
* @param string $value Value of config
* @param string $key Name of config
* @return string
*/
public function pwa_short_sitename($value, $key)
{
$placeholder = $this->get_shortname($this->config['sitename']);

return '<input id="' . $key . '" type="text" size="40" maxlength="12" name="config[' . $key . ']" value="' . $value . '" placeholder="' . $placeholder . '">';
}

/**
* Validate PWA options
*
Expand All @@ -188,40 +203,79 @@ public function pwa_icon_name($value, $key)
*/
public function validate_pwa_options($event)
{
// Ignore validation if icon fields are empty
if ($event['config_definition']['validate'] !== 'pwa_options' || (empty($event['cfg_array']['pwa_icon_small']) && empty($event['cfg_array']['pwa_icon_large'])))
{
return;
}
$type = 0;
$mode = 1;

$value = $event['cfg_array'][$event['config_name']];
$validator = explode(':', $event['config_definition']['validate']);

// Don't allow empty values, if one icon is set, both must be set.
if (empty($value))
if ($validator[$type] !== 'pwa_options')
{
$this->add_error($event, 'PWA_IMAGE_NOT_PROVIDED', $this->language->lang(strtoupper($event['config_name'])));
return;
}

// Check if image is valid
$image = $this->root_path . $this->config['icons_path'] . '/' . $value;
$image_info = $this->imagesize->getImageSize($image);
if ($image_info !== false)
switch ($validator[$mode])
{
if (($event['config_name'] === 'pwa_icon_small' && $image_info['width'] !== 192 && $image_info['height'] !== 192) ||
($event['config_name'] === 'pwa_icon_large' && $image_info['width'] !== 512 && $image_info['height'] !== 512))
{
$this->add_error($event, 'PWA_ICON_SIZE_INVALID', $value);
}

if ($image_info['type'] !== IMAGETYPE_PNG)
{
$this->add_error($event, 'PWA_ICON_MIME_INVALID', $value);
}
}
else
{
$this->add_error($event, 'PWA_IMAGE_INVALID', $value);
case 'string':
// Ignore validation if icon fields are empty
if (empty($event['cfg_array']['pwa_short_name']))
{
return;
}

$short_name = $event['cfg_array']['pwa_short_name'];

// Do not allow multibyte characters or emoji
if (strlen($short_name) !== mb_strlen($short_name, 'UTF-8'))
{
$this->add_error($event, 'PWA_SHORT_NAME_INVALID');
return;
}

// Do not allow strings longer than 12 characters
if (strlen($short_name) > 12)
{
$this->add_error($event, 'PWA_SHORT_NAME_INVALID');
return;
}
break;

case 'icons':
// Ignore validation if icon fields are empty
if (empty($event['cfg_array']['pwa_icon_small']) && empty($event['cfg_array']['pwa_icon_large']))
{
return;
}

$value = $event['cfg_array'][$event['config_name']];

// Don't allow empty values, if one icon is set, both must be set.
if (empty($value))
{
$this->add_error($event, 'PWA_IMAGE_NOT_PROVIDED', $this->language->lang(strtoupper($event['config_name'])));
return;
}

// Check if image is valid
$image = $this->root_path . $this->config['icons_path'] . '/' . $value;
$image_info = $this->imagesize->getImageSize($image);
if ($image_info !== false)
{
if (($event['config_name'] === 'pwa_icon_small' && $image_info['width'] !== 192 && $image_info['height'] !== 192) ||
($event['config_name'] === 'pwa_icon_large' && $image_info['width'] !== 512 && $image_info['height'] !== 512))
{
$this->add_error($event, 'PWA_ICON_SIZE_INVALID', $value);
}

if ($image_info['type'] !== IMAGETYPE_PNG)
{
$this->add_error($event, 'PWA_ICON_MIME_INVALID', $value);
}
}
else
{
$this->add_error($event, 'PWA_IMAGE_INVALID', $value);
}
break;
}
}

Expand Down Expand Up @@ -251,4 +305,15 @@ protected function can_use_notifications()
&& ANONYMOUS !== $this->user->id()
&& USER_IGNORE !== (int) $this->user->data['user_type'];
}

/**
* Get short name from a string (strip out multibyte characters and trim to 12 characters)
*
* @param string $name
* @return string 12 max characters string
*/
protected function get_shortname($name)
{
return utf8_substr(preg_replace('/[^\x20-\x7E]/', '', $name), 0, 12);
}
}
3 changes: 2 additions & 1 deletion language/en/webpushnotifications_common_acp.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
$lang = array_merge($lang, [
'PWA_SETTINGS' => 'Progressive web application options',
'PWA_SHORT_NAME' => 'Short site name',
'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.',
'PWA_SHORT_NAME_EXPLAIN' => 'Your site name in 12 characters or fewer, which may be used as a label for an icon on a mobile device’s home screen. (If this field is left empty, the first 12 characters of the <samp>Site name</samp> will be used.)',
'PWA_SHORT_NAME_INVALID' => '“Short site name” contains illegal characters or exceeds the 12 character limit.',
'PWA_ICON_SMALL' => 'Small mobile device icon',
'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.',
'PWA_ICON_LARGE' => 'Large mobile device icon',
Expand Down
17 changes: 16 additions & 1 deletion styles/all/template/event/overall_header_head_append.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
<!-- Ensure the app can be added to the home screen on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">

<!-- Ensure the app can be added to the home screen on Chrome -->
<meta name="mobile-web-app-capable" content="yes">

<!-- Sets the status bar style when the app is launched from the home screen on iOS -->
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="{{ SITENAME }}">

<!-- The name of your app when saved to the iOS home screen -->
<meta name="apple-mobile-web-app-title" content="{{ SHORT_SITE_NAME }}">

<!-- The name of your app when saved to other browsers and platforms -->
<meta name="application-name" content="{{ SHORT_SITE_NAME }}">

<!-- Link to app's configuration manifest -->
<link rel="manifest" href="{{ U_MANIFEST_URL }}">

<!-- App icon for iOS, a fallback to icons defined in the manifest -->
{% if U_TOUCH_ICON %}<link rel="apple-touch-icon" href="{{ T_ICONS_PATH ~ U_TOUCH_ICON }}">{% endif %}

{% if NOTIFICATIONS_WEBPUSH_ENABLE %}
Expand Down
46 changes: 39 additions & 7 deletions tests/event/listener_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ public function test_load_template_data($user_id, $method_data, $subscriptions,
public function test_pwa_manifest()
{
$this->config['pwa_icon_small'] = 'icon-192x192.png';
$this->config['pwa_short_name'] = 'Test';

$this->set_listener();

Expand All @@ -270,6 +271,7 @@ public function test_pwa_manifest()
->with([
'U_MANIFEST_URL' => $this->controller_helper->route('phpbb_webpushnotifications_manifest_controller'),
'U_TOUCH_ICON' => 'icon-192x192.png',
'SHORT_SITE_NAME' => 'Test',
]);

$dispatcher = new \phpbb\event\dispatcher();
Expand Down Expand Up @@ -332,48 +334,78 @@ public function validate_pwa_options_data()
{
return [
[
'pwa_options:icons',
['pwa_icon_small' => '192.png', 'pwa_icon_large' => '512.png'],
[],
],
[
'pwa_options:icons',
['pwa_icon_small' => '1.png', 'pwa_icon_large' => '512.png'],
['PWA_ICON_SIZE_INVALID'],
],
[
'pwa_options:icons',
['pwa_icon_small' => '1.png', 'pwa_icon_large' => '12.png'],
['PWA_ICON_SIZE_INVALID'],
],
[
'pwa_options:icons',
['pwa_icon_small' => '192.jpg', 'pwa_icon_large' => '512.gif'],
['PWA_ICON_MIME_INVALID'],
],
[
'pwa_options:icons',
['pwa_icon_small' => '', 'pwa_icon_large' => ''],
[],
],
[
'pwa_options:string',
['pwa_short_name' => 'foo'],
[],
],
[
'pwa_options:string',
['pwa_short_name' => ''],
[],
],
[
'pwa_options:string',
['pwa_short_name' => 'foo❤️'],
['PWA_SHORT_NAME_INVALID'],
],
[
'pwa_options:string',
['pwa_short_name' => str_repeat('a', 50)],
['PWA_SHORT_NAME_INVALID'],
],
];
}

/**
* @dataProvider validate_pwa_options_data
*/
public function test_validate_pwa_options($cfg_array, $expected_error)
public function test_validate_pwa_options($validate, $cfg_array, $expected_error)
{
$this->config['icons_path'] = 'images/icons';
$config_name = key($cfg_array);
$config_definition = ['validate' => 'pwa_options'];
$small_image = $cfg_array['pwa_icon_small'] ? explode('.', $cfg_array['pwa_icon_small']) : ['', ''];
$large_image = $cfg_array['pwa_icon_large'] ? explode('.', $cfg_array['pwa_icon_large']) : ['', ''];
$config_definition = ['validate' => $validate];

$pwa_icon_small = isset($cfg_array['pwa_icon_small']) ? $cfg_array['pwa_icon_small'] : '';
$pwa_icon_large = isset($cfg_array['pwa_icon_large']) ? $cfg_array['pwa_icon_large'] : '';

[$small_image_name, $small_image_ext] = $pwa_icon_small ? explode('.', $pwa_icon_small, 2) : ['', ''];
[$large_image_name, $large_image_ext] = $pwa_icon_large ? explode('.', $pwa_icon_large, 2) : ['', ''];

$error = [];

$this->set_listener();

$this->imagesize->expects(self::any())
$this->imagesize->expects($pwa_icon_small && $pwa_icon_large ? self::once() : self::never())
->method('getImageSize')
->willReturnMap([
[$this->root_path . $this->config['icons_path'] . '/', '', false],
[$this->root_path . $this->config['icons_path'] . '/' . $cfg_array['pwa_icon_small'], '', ['width' => (int) $small_image[0], 'height' => (int) $small_image[0], 'type' => $small_image[1] === 'png' ? IMAGETYPE_PNG : IMAGETYPE_UNKNOWN]],
[$this->root_path . $this->config['icons_path'] . '/' . $cfg_array['pwa_icon_large'], '', ['width' => (int) $large_image[0], 'height' => (int) $large_image[0], 'type' => $large_image[1] === 'png' ? IMAGETYPE_PNG : IMAGETYPE_UNKNOWN]],
[$this->root_path . $this->config['icons_path'] . '/' . $pwa_icon_small, '', ['width' => (int) $small_image_name, 'height' => (int) $small_image_name, 'type' => $small_image_ext === 'png' ? IMAGETYPE_PNG : IMAGETYPE_UNKNOWN]],
[$this->root_path . $this->config['icons_path'] . '/' . $pwa_icon_large, '', ['width' => (int) $large_image_name, 'height' => (int) $large_image_name, 'type' => $large_image_ext === 'png' ? IMAGETYPE_PNG : IMAGETYPE_UNKNOWN]],
]);

$dispatcher = new \phpbb\event\dispatcher();
Expand Down

0 comments on commit 02babec

Please sign in to comment.