Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Push notifications #429

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 45 additions & 0 deletions application/Controller/PwaController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

class PwaController extends Controller {

public function __construct(Site &$site) {
parent::__construct($site);
if (!Request::isAjaxRequest()) {
$default_assets = get_default_assets('site');
$this->registerAssets($default_assets);
}
}

public function pwaAction() {
error_log('pwaAction in PwaController called');



}

public function subscribeAction() {
$_POST = json_decode(file_get_contents('php://input'), true);
$run = new Run($this->getDB(), $_POST['runname']);

try {
$this->getDB()->insert('survey_push_subscriptions', array(
'run_id' => $run->id,
'endpoint' => $_POST['endpoint'],
'auth' => $_POST['auth'],
'p256dh ' => $_POST['p256dh'],
'session' => Site::getCurrentUser()->user_code
));

} catch (Exception $e) {
error_log($e->getMessage());

}

}

public function indexAction() {
error_log('indexAction of PwaController');
}


}
43 changes: 43 additions & 0 deletions application/Model/Email.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<?php

use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;

class Email extends RunUnit {

public $errors = array();
Expand Down Expand Up @@ -464,6 +467,7 @@ protected function sessionCanReceiveMails() {
}

public function exec() {
$this->execPushNotifications();
// If emails should be sent only when cron is active and unit is not called by cron, then end it and move on
if ($this->cron_only && !$this->called_by_cron) {
$this->end();
Expand All @@ -484,4 +488,43 @@ public function exec() {
return array('body' => $err);
}

private function execPushNotifications() {
error_log('email unit execPushNotifications: ' . $this->run_session->session);

$push_auth = Config::get('push_auth');

$stmt = $this->dbh->prepare('SELECT * FROM survey_push_subscriptions WHERE run_id = ? and session LIKE ?');
$stmt->execute(array($this->run->id, $this->run_session->session));

if ($stmt->rowCount() > 0) {
error_log('Datenbankeinträge Push-Subscriptions: ' . $stmt->rowCount());

$notifications = array();
foreach ($stmt->fetchAll() as $row) {
error_log('Push-Sub: ' . $row['endpoint']);
$notifications[] = [
'subscription' => Subscription::create([
'endpoint' => $row['endpoint'],
'publicKey' => $row['p256dh'],
'authToken' => $row['auth']
]),
'payload' => '{msg: "Please continue your survey!", url: "' . run_url($this->run->name) . '"}'
];
}

$webPush = new WebPush($push_auth);
foreach ($notifications as $notification) {
$webPush->sendNotification($notification['subscription'], $notification['payload']);
}
foreach ($webPush->flush() as $report) {
$endpoint = $report->getRequest()->getUri()->__toString();

if ($report->isSuccess()) {
error_log("[v] Message sent successfully for subscription {$endpoint}.");
} else {
error_log("[x] Message failed to sent for subscription {$endpoint}: {$report->getReason()}");
}
}
}
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"phpmailer/phpmailer": "5.*",
"bshaffer/oauth2-server-php": "~1.7",
"atrox/haikunator": "^1.0",
"paragonie/halite": "^4"
"paragonie/halite": "^4",
"minishlink/web-push": "^5.2"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
Expand Down
3 changes: 2 additions & 1 deletion setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
'admin/mail' => 'AdminMailController',
'superadmin' => 'SuperadminController',
'api' => 'ApiController',
'run' => 'RunController'
'run' => 'RunController',
'pwa' => 'PwaController'
);

// Load application settings
Expand Down
11 changes: 11 additions & 0 deletions sql/patches/031_push_subscriptions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE `survey_push_subscriptions` (
`run_id` int(11) NOT NULL,
`endpoint` varchar(500) NOT NULL,
`auth` varchar(45) NOT NULL,
`p256dh` mediumtext,
`session` char(64) NOT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_index` (`run_id`,`endpoint`,`session`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;

3 changes: 2 additions & 1 deletion templates/public/head.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
H.className = H.className.replace(/\bno_js\b/, 'js')
})(document.documentElement)</script>
<title><?php echo $site->makeTitle(); ?></title>
<link rel="manifest" type="application/manifest+json" href="manifest.json">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
Expand Down Expand Up @@ -33,4 +34,4 @@
print_scripts($files, $id);
}
?>
<link rel="icon" href="<?php echo site_url('favicon.ico'); ?>">
<link rel="icon" href="<?php echo site_url('favicon.ico'); ?>">
99 changes: 99 additions & 0 deletions webroot/assets/common/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,102 @@ function cookies_enabled() {
}
});
}(jQuery));


if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js')
.then(function(reg) {
console.log('SW successfully installed');
configurePushSub();
}).catch(function(error) {
console.log('Registration failed with ' + error);
});
}

function urlBase64ToUint8Array(base64String) {
var padding = '='.repeat((4 - base64String.length % 4) % 4);
var base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');

var rawData = window.atob(base64);
var outputArray = new Uint8Array(rawData.length);

for (var i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}

function configurePushSub() {
if (!('serviceWorker' in navigator)) {
return;
}

var reg;
navigator.serviceWorker.ready
.then(function(swreg) {
reg = swreg;
return swreg.pushManager.getSubscription();
})
.then(function(sub) {
if (sub === null) {
var vapidPublicKey = 'BMjkOGYKy_sFVci1vCMhshyyJEoPS_sAyCuzYs4tImm6FMsF9FZu9pDrQnCnT88gVENH8ABLP3Ci7jUNaFPk8kQ';
console.log('vapidPublicKey: ' . vapidPublicKey);
var convertedVapidPublicKey = urlBase64ToUint8Array(vapidPublicKey);
console.log(convertedVapidPublicKey);
var retval = reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidPublicKey
});
return retval;
}
return sub;
})
.then(function(newSub) {
pushsubscriptionobject = newSub;
console.log(newSub);
jsonfied_subscription = JSON.parse(JSON.stringify(newSub));
fetch('https://www.uni-muenster.de/PsyTD/formr-entwicklung/pwa/subscribe', {
method: 'POST',
credentials: "same-origin",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(
{
'endpoint': jsonfied_subscription.endpoint,
'auth': jsonfied_subscription.keys.auth,
'p256dh': jsonfied_subscription.keys.p256dh,
'runname': window.location.href.replace(/.*\//, '')
})
});


return newSub
})
.then(function(res) {
if (res.ok) {
displayConfirmNotification();
}
})
.catch(function(err) {
console.log(err);
});
}

$(document).ready(function() {
if ('Notification' in window) {
Notification.requestPermission().then(function(permission) {
if (permission === 'denied') {
console.log('Permission for notifications wasn\'t granted.');
return;
}
if (permission === 'default') {
console.log('Permissions still on default.');
return;
}
});
}
});
Binary file added webroot/assets/site/img/icons/icon-128x128.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webroot/assets/site/img/icons/icon-144x144.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webroot/assets/site/img/icons/icon-152x152.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webroot/assets/site/img/icons/icon-192x192.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webroot/assets/site/img/icons/icon-384x384.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webroot/assets/site/img/icons/icon-512x512.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webroot/assets/site/img/icons/icon-72x72.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webroot/assets/site/img/icons/icon-96x96.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webroot/assets/site/img/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions webroot/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "Formr",
"theme_color": "#99cc53",
"background_color": "#000000",
"display": "browser",
"Scope": "PsyTD/formr-entwicklung",
"start_url": "https://www.uni-muenster.de/PsyTD/formr-entwicklung",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to check if we can insert this dynamically.

"icons": [
{
"src": "assets/site/img/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "assets/site/img/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "assets/site/img/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "assets/site/img/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "assets/site/img/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "assets/site/img/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "assets/site/img/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "assets/site/img/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"splash_pages": null,
"gcm_sender_id": "103953800507"
}
70 changes: 70 additions & 0 deletions webroot/sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const SW_VERSION = 'formr-v0.0.15'

notification_options = {
"body": "This is a formr notification.",
"icon": "assets/site/img/logo.png",
"image": "assets/site/img/logo.png",
"vibrate": [5,0,5,0,5],
"requireInteraction": true,
tag: 'renotify',
renotify: true,
// actions: [
// {action: 'open', title: 'Go to survey'}
// ]
}

function dispatchNotification() {
console.log('dispatchingNotification');
self.registration.showNotification('Please continue your Survey', notification_options);

}



self.addEventListener('install', function(event) {
console.log(`Formr-Service-Worker Version ${SW_VERSION} installed`);
});

self.addEventListener('activate', function(event) {
console.log(`Formr-Service-Worker Version ${SW_VERSION} activated`);
});


self.addEventListener('push', function(event) {
console.log('Got a push event');
if (!(self.Notification && self.Notification.permission === 'granted')) {
return;
}
dispatchNotification();
});

self.addEventListener('notificationclick', function(event) {
var notification = event.notification;
var action = event.action;

console.log(notification);

if (action === 'confirm') {
console.log('Confirm was chosen');
notification.close();
} else {
console.log(action);
event.waitUntil(
clients.matchAll()
.then(function(clis) {
var client = clis.find(function(c) {
return c.visibilitystate === 'visible';
});

if (client !== undefined) {
client.navigate('https://www.uni-muenster.de/PsyTD/formr-entwicklung/NeuesQueuingSystemTest');
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The link to the run needs to be inserted here. Should be part of the push notification.

client.focus();
} else {
clients.openWindow('https://www.uni-muenster.de/PsyTD/formr-entwicklung/NeuesQueuingSystemTest');
}
notification.close();
})
);
}

});