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 all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions application/Controller/PwaController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?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']);

error_log('Register push subscription: ' . $run->id . ', ' . Site::getCurrentUser()->user_code);
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');
}


}
51 changes: 51 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 @@ -477,11 +480,59 @@ public function exec() {

// Try to send email
$err = $this->sendMail();
$this->execPushNotifications();
if ($this->mail_sent) {
$this->end();
return false;
}
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 ?');
error_log('run-d: ' . $this->run->id);
error_log('session-d: ' . $this->run_session->session);
$stmt->execute(array($this->run->id, $this->run_session->session));

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

$webPush = new WebPush($push_auth);
$notifications = array();
foreach ($stmt->fetchAll() as $row) {
error_log('Push-Sub: ' . $row['endpoint']);
if (strpos($row['endpoint'], 'mozilla') > 0) {
$webPush->setAutomaticPadding(0);
}
$notifications[] = [
'subscription' => Subscription::create([
'endpoint' => $row['endpoint'],
'publicKey' => $row['p256dh'],
'authToken' => $row['auth']
]),
'payload' => '{"msg": "' . $this->body_parsed . '", "url": "' . run_url($this->run->name) . '"}'
];
error_log('body: ' . $this->body_parsed);
error_log('payload: ' . $notifications[sizeof($notifications)-1]['payload']);
}

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-emotions/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(/.*\//, '').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
Loading
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
Loading
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
Loading
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
Loading
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
Loading
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
Loading
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
Loading
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
Loading
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
Loading
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"
}
76 changes: 76 additions & 0 deletions webroot/sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const SW_VERSION = 'formr-v0.0.15'

function dispatchNotification() {
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) {
if (!(self.Notification && self.Notification.permission === 'granted')) {
return;
}

if (event.data) {
var data = event.data.json();
}
let notification_options = {
"icon": "assets/site/img/logo.png",
"image": "assets/site/img/logo.png",
"vibrate": [300,100,400],
"requireInteraction": true,
"data": data,
tag: 'renotify',
renotify: true,
}
console.log(data.msg);

self.registration.showNotification(data.msg, notification_options);

//dispatchNotification();
});

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

if (event.notification.data) {
console.log(event.notification.data);
console.log(event.notification.data.msg);
console.log(event.notification.data.url);
}

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';
});
console.log(client);

if (client !== undefined) {
client.navigate(event.notification.data.url);
client.focus();
} else {
clients.openWindow(event.notification.data.url);
}
notification.close();
})
);
}

});