-
Notifications
You must be signed in to change notification settings - Fork 136
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
Add firebase cloud messaging and browser push #491
Conversation
I changed the plan a bit from #394 - There are two concepts:
I realised just storing the tokens in the database does not reflect intention properly. To support removing all registrations in one go it would need to keep the registration but mark it for removal, so when that browser connects again it can uninstall itself. This seems complicated and not especially useful. Part of the complexity is that you cannot assume the registration tokens will stay the same forever, and the browser can always get one. If intention were stored in the database the browser would need an identifier so it can know which registration is intended for it (or maybe add something to the session). But again, getting complicated and little benefit right now. I changed it so you so that now you and enable/disable push for the current browser you are using, and nothing else. The intention is stored in the browser (in a cookie), and the client app does it's best to make it so. I think this fits well to how mobile works too. So UX is nice and simple and looks like: Thoughts? And some tasks from the issue:
|
This would be at
I like it! We will probably want to nag users who don't have it checked by asking them if they want to enable it, store that we've nagged them to the browser session and ask again only when they login with new browser. But that can be the next step once this PR is done.
You can just add an example config block to
Another feature for another PR. :-)
Link to the message thread. Just add analytics tags to the URL, see an example. |
Yup, getting it working and live first seems more useful, make sure it actually works... I think it's pretty easy to get too naggy and annoying with push. I suspect it will be better to notify on every new message too. I believe you can tag the messages too such that newer ones replace older ones so they don't stack up. |
Aha, my fight with travis was victorious! 🥇 |
Yep. What's up with the change to Firefox? PR looks great! |
PhantomJS doesn't have much of the newer browser stuff supported and I'd like to add tests for the browser notifications. Although using PhantomJS locally (same version too, 2.1.1 iirc) doesn't fail in the tests (isSupported gets set to false) but in travis it failed inside the firebase js lib because Would be good to check it more properly with an unsupported browser to make sure it works fine. |
@simison Don't you have your own account? Anyway, I've just shared the login with you. @nicksellen If you send me your lastpass email I can share it with you. |
Don't you have your own account? Anyway, I've just shared the login with you.
Sure, but for some reason I couldn’t see the password nor share that one.
Thanks!
… On 12 Apr 2017, at 14.15, Callum Macdonald ***@***.***> wrote:
@simison Don't you have your own account? Anyway, I've just shared the login with you.
@nicksellen If you send me your lastpass email I can share it with you.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
There are nice tests now :) It was quite a battle to get karma/etc to be happy, so easy to lose track of a promise somewhere... I split the client service into [1]
|
F*** you Travis! |
Ready for review! Just a few things to look at #491 (comment) |
firebase.token = token; | ||
|
||
// .. and enable it to be initialized | ||
firebaseMessaging.shouldInitialize = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set this to false in a beforeEach
hook
|
||
// Attempt to initialize Facebook SDK on first page load | ||
// If this fails, we'll try this again on successfull login | ||
Facebook.init(); | ||
|
||
push.init(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A short comment over this could do. :-)
@@ -22,6 +22,9 @@ module.exports = function(app) { | |||
// Return a 404 for all undefined api, module or lib routes | |||
app.route('/:url(api|modules|lib|developers)/*').get(core.renderNotFound); | |||
|
|||
// Gives the service worker access to any config it needs | |||
app.route('/config/sw.js').get(core.renderServiceWorkerConfig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally these been exposed to index html template from config/lib/express.js.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The service worker does not have access to the HTML/DOM. It's very restricted.
Perhaps a better option is sending a message to it once it's started up [1]. I'm not very happy with the current approach.
[1] http://craig-russell.co.uk/2016/01/29/service-worker-messaging.html
exports.renderServiceWorkerConfig = function(req, res) { | ||
res.set('Content-Type', 'text/javascript') | ||
.send('var FCM_SENDER_ID = ' + JSON.stringify(config.fcm.senderId) + ';\n'); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ExpressJS has support for jsonp, but normally configs have been exposed to index html template from config/lib/express.js.
|
||
messaging.setBackgroundMessageHandler(function(payload) { | ||
// not actually used, but without it here firefox does not receive messages... | ||
console.log('received payload', payload); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function never gets fired but it has to be there? messaging.setBackgroundMessageHandler(Function.prototype)
might be handy.
Also if Angular is already in window
at this point, angular.noop is available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No angular here, the service worker is a standalone script and they run with a limited environment.
firebase/quickstart-js#71 has a discussion about it the background handler stuff - the gist is that by sending a notification payload (as opposed to data) you are specifying it should be a regular notification, and not be overridable.
my suspicion about why it didn't work without that in firefox is that without defining some kind of listener it stops listening for new messages. it would be useful to verify it properly though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okidoki, thanks for clarifying!
|
||
importScripts('/lib/firebase/firebase-app.js'); | ||
importScripts('/lib/firebase/firebase-messaging.js'); | ||
importScripts('/config/sw.js'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, now I understood why the config was loaded like it was earlier! Ignore my earlier comments about this.
We should probably move all the configs to load like this. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I liked them in index.html
. This way would be 1 extra http request too, but could load the config into a standard TrustrootsConfig
object or something. I'm easy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They're handy in index.html
indeed but stops making the app work self hosted and offline (e.g. on mobile). It's another discussion and another PR anyway.
package.json
Outdated
@@ -140,6 +141,7 @@ | |||
"nodemailer-stub-transport": "~1.1.0", | |||
"phantomjs-prebuilt": ">=2.1", | |||
"promise": "~7.1.1", | |||
"proxyquire": "^1.7.11", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
~
just for consistency.
package.json
Outdated
@@ -61,6 +61,7 @@ | |||
"express-paginate": "~0.2.1", | |||
"express-session": "~1.14.0", | |||
"fbgraph": "~1.3.0", | |||
"firebase-admin": "^4.2.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
~
just for consistency.
pushService.sendUserNotification(user, { | ||
title: 'Trustroots', | ||
body: 'A ' + platform + ' push device was added!', | ||
click_action: 'http://localhost:3000/profile/edit/account' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might work here better for flexibility with different setups (Docker IP, https):
var protocol = (config.https === true || req.protocol === 'https') ? 'https' : 'http';
var host = protocol + '://' + req.get('host'); // http://localhost:3000
...or actually this might be already available as res.locals.hostPort
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, I forgot to fix that bit.
I also wonder whether it would be a good idea to send a notification at that point in production too, but only to the device you just added?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, maybe in development some other way to send notifications could be handy for manual testing/playing purposes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also wonder whether it would be a good idea to send a notification at that point in production too, but only to the device you just added?
Yeah I think so, it kinda confirms to the user that it worked.
So to send push to all the devices, just remove that if
? I think it's okay to send it to all the devices even (how many there can be), just to avoid extra work. Feels kind of a security feature even in that way anyway. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy could be something like "You just enabled Trustroots platform
push notifications. Yay!"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, sounds good :)
</div> | ||
|
||
<p class="help-block" ng-if="profileEditAccount.push.isSupported"><small>This will send notifications even when the website is closed.</small></p> | ||
<p class="help-block" ng-if="!profileEditAccount.push.isSupported"><small>Your browser does not support push notifications.</small></p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When unsupported, the whole block could just be hidden?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did it that way so it communicates: if you use another browser then you can get push notifications
It also helps to keep a consistent interface, so users don't get confused wondering where the option went when they had it available on another browser.
I don't feel that strongly about it though. Happy to hide it all if unsupported if you prefer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good thinking 👍, let's leave it visible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an old script for automated testing: https://github.com/Trustroots/trustroots/tree/master/scripts/selenium ...but frankly I'm not too keen to keep that up to date. I think manual testing and those few unit tests are great, we should notice pretty quick if it fails, esp. if we push some events to Influx stats. |
bower.json
Outdated
@@ -4,6 +4,7 @@ | |||
"dependencies": { | |||
"angular": "1.5.8", | |||
"angular-animate": "1.5.8", | |||
"angular-cookies": "1.5.8", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW there's already https://github.com/tymondesigns/angular-locker which might save you some kb's since no need to add this lib, but I'm fine either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems a good idea
... it sends it to all devices for now
source: 'push-notification', | ||
medium: 'fcm', | ||
campaign: 'device-added', | ||
content: 'reply-to' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what this should be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
medium
could probably be just push-notification
, I'm not sure if we gonna differentiate different platforms in the future but doesn't matter for now.
Since there is just one place (notification click) pointing to the same url, content
can probably be left empty. It's used to make difference e.g. between different parts of email linking to the same URL (e.g. "footer" and "header"). ...I think.
They're explained in this doc and at query builder
No stress over these, we can adjust them later.
Hmm a weird error from a simple change:
Investigating... |
Aha, |
@simison not sure why the pr build fails so frequently when the push one seems fine? I don't think there is an actual error. One thing I haven't done is tried it in other browsers, but this is not totally simple because the security stuff requires https when not using localhost, so I can't access it from my phone via my machines ip address. One solution would be to setup https locally, but also need to change a few settings to use |
Perhaps someone at least has a windows machine or mac to try it on though? |
I'll build this to dev machine, just a mo. Edit: done! |
Switching to Firefox is probably "causing" frontend Karma tests to fail now, but I'm not sure why exactly. Might be just some |
Tried it on dev.trustroots.org on desktop and mobile, it all works! ChromeChrome did not show the notification when the browser tab was the active one on the screen, but did when the tab was closed, and when the browser was not in the foreground. Not actually sure about if the browser is completely closed (I guess not). When loading the site again after enable notifications it asked me if I wanted to add it to the home screen (so I suspect it only gets used once a web worker has been installed). The notification icon is the chrome icon. FirefoxFirefox always showed the notification (well, didn't try with browser completely closed, I guess not). The notification icon is the firefox icon. Android browser (not supported) |
Great! So my todo seems to be:
My goal is to get this live some time Thu—Sat. |
Firebase is more abstracted now so should cause less problems not having all the latest browser APIs.
I do not feel motivated to try and fix it for this issue. I think it could take some time and is not really related to the push features. Actually it might be possible to switch to back to PhantomJS as I have abstracted the firebase stuff further away now - just pushed a commit to revert it (although I think it will have to change again eventually now the maintainer stepped down). |
I just checked, our Karma is 1.3.0 and newest is 1.6.0 so that might be causing it as well. Updating Karma + switching to Firefox seems like a separate, not so urgent PR. |
Related to #491 "Add firebase cloud messaging and browser push"
Initial work only.
Currently only pushes messages when you register for push.
Need to have
firebase.json
in project root with service account credentials from FCM. Will move to config somewhere in future.No tests yet...