safwanrahman / django-webpush Goto Github PK
View Code? Open in Web Editor NEWWeb Push Notification Package for Django
License: GNU General Public License v3.0
Web Push Notification Package for Django
License: GNU General Public License v3.0
The repo on PyPi was last updated in 2019. Please update it there to fix issues with Django 4 and allow customisation of subscribe button.
Chrome needs manifest.json
to be available in the page while asking for Push notification registration. Otherwise it will throw a error
Uncaught (in promise) DOMException: Registration failed - manifest empty or missing
So for adding support for chrome, we need to add a menifest.json
to the directory. An example of menifest.json can be found here. The instruction can be found in MDN
In the menifest.json
there is a field for gcm_sender_id
. This can be obtained from the google console.
It should be possible for the developer to configure the gcm_sender_id
in the settings so that its possible to get it from there.
We should find out a way to get it from settings and generate a json so that it will be possible to load the json in the page with the templatetags
Recently, pywebpush 0.4.0 is released. Which enable sending notification to chrome broswer. We need to upgrade to pywebpush 0.4.0
.
Be mentioned that, as we dont have any test, we just need to test manually if everything works.
hi
I am in a situation changing the appearance of webpush_button. I dont want to change webpush package in my project. Is there a way to change it in my template? for example I dont want a button, instead I want a with specific class. How should I do this?
thanks
Currently these variables are in global scope:
var isPushEnabled = false,
subBtn,
messageBox,
registration;
Also these methods: subscribe
, unsubscribe
, postSubscribeObj
.
This is a bad practive especially because their names are common to use. To prevent that we can at least put everything inside window load event handler:
window.addEventListener('load', function() {
// Place it here
});
Hi,
I am using using Django Rest Rramework.
I got the package working with all setup in place, The API to save information is called and executed successfully. The only problem right now is that the user information is not saved. My findings say that this is because I am using DRF. The way DRF injects a user into the request is may be different from how the traditional Django does. And hence the request.user
in the view of the package in not found.
Right now i am thinking to make a clone of the repo and make changes directly in order to debug and find the exact issue/solution.
Kindly let me know what would be the right way. Or is there is a existing solution to this already.
Thanks
Your document is not correct!
<head>
<meta charset="utf-8"/>
<title>Chat Rooms</title>
{% load webpush_notifications %}
{% webpush_header %}
{# {{ webpush_header() }}#}
</head>
<body>
<div id="webpush">
<span>notifications</span>
{% webush_button %}
{# {{ webush_button() }}#}
</div>
</body>
could you write down your document in more specific detail ?
Django==2.0.6
django-webpush==0.2.4
Hi,
First I want to say thank you for this amazing package!
I am getting this error when trying to subscribe using chrome:
django.core.exceptions.FieldError: Invalid field name(s) for model SubscriptionInfo: 'expirationTime'.
I tried to remove the field 'expirationTime' from the dictionary under views:
`# We at least need the user or group to subscribe for a notification
if request.user.is_authenticated() or group_name:
# Save the subscription info with subscription data
# as the subscription data is a dictionary and its valid
print(subscription_data)
subscription_data.pop('expirationTime')
subscription = subscription_form.get_or_save(subscription_data)
web_push_form.save_or_delete(
subscription=subscription, user=request.user,
status_type=status_type, group_name=group_name)
# If subscribe is made, means object is created. So return 201
if status_type == 'subscribe':
return HttpResponse(status=201)
# Unsubscribe is made, means object is deleted. So return 202
elif "unsubscribe":
return HttpResponse(status=202)`
And it worked but sending notifications to the subscribed browser is not working.
By the way Firefox is working great.
Please help,
Thanks!
If a Firefox user has disabled notifications globally by setting dom.webnotifications.enabled:false in prefs (like me!), there will be no Notification object. webpush.js needs to check whether it exists before trying to test its properties.
See also https://miketaylr.com/posts/2017/02/how-not-to-feature-detect.html which helped me work out the problem after a lot of searching. I had forgotten that I disabled notifications.
Thanks!
TypeError: unhashable type is now thrown when attempting to send
a notifcation.
I am seeing the error attempt to send a notification using the following code:
from webpush import models, utils
sub = subscription=models.SubscriptionInfo.objects.get(browser='chrome')
push = models.PushInformation.objects.get(subscription=sub); utils._send_notification(push, {"header": "what", "body": "up"}, 100)
error:
Traceback (most recent call last):
File "", line 1, in
File "/home/jscarlett/venv/adm/local/lib/python2.7/site-packages/webpush/utils.py", line 30, in send_notification
req = WebPusher(subscription_data).send(data=payload, ttl=ttl, gcm_key=gcm_key)
File "/home/jscarlett/venv/adm/local/lib/python2.7/site-packages/pywebpush/__init_.py", line 175, in send
encoded = self.encode(data)
File "/home/jscarlett/venv/adm/local/lib/python2.7/site-packages/pywebpush/init.py", line 147, in encode
authSecret=self.auth_key)
File "/home/jscarlett/venv/adm/local/lib/python2.7/site-packages/http_ece/init.py", line 152, in encrypt
result += encryptRecord(key_, nonce_, counter, buffer[i:i+rs])
TypeError: unhashable type
I was able to fix it by adding this check to the encode method of pywebpush: https://gist.github.com/jamaalscarlett/b791886a206b0fb3ad1c348877298509#file-__init__-py-L23
but I think the validation should probably be done in this library.
Currently all informing messages for user are hardcoded as js strings, for example:
messageBox.textContent = 'Service Worker is not supported in your Browser!';
Translation to different language requires copying whole js and translating these strings.
So currently, clicking on the notification do nothing. So it can be only used to show notification. Not possible to send a notification that user can click on the notification and they will be redirect to any link.
So we should implement that the sender can configure a url to which the receiver will be taken while he clicks on the notification.
So it will work like following:
So it needs some backend work and most of the javascript work.
Button can be for example simple icon without any text with bell changing to icon with crossed "X" for unsubscribing.
Or like in my case it can contain both icon and text (I use Bootstrap 3 Glyphicons):
<button class="btn btn-default" id="webpush-subscribe-button" {% if group %}data-group="{{ group }}"{% endif %} data-url="{{ url }}">
<span class="glyphicon glyphicon-bell"></span> Подписаться
</button>
Then using:
subBtn.textContent = 'Subscribe to Push Messaging';
is not acceptable.
For my case I used this method:
function changeSubBtnText(subscribe) {
if (subscribe === undefined) {
subscribe = true;
}
var text = subscribe ? 'Подписаться' : 'Отписаться';
subBtn.innerHTML = '<span class="glyphicon glyphicon-bell"></span> ' + text;
}
and then I call changeSubBtnText()
for subscribing state and changeSubBtnText(false)
for unsubscribing state.
In webpush.html
template used by {% webpush %}
template tag there is div
element storing some webpush related data:
<div id="webpush-data" {% if group %} data-group="{{ group }}" {% endif %} data-url="{{ url }}" hidden></div>
1) If this tag will be included in head
section (and README says to add it there), then to have div
inside HTML head
tag will be semantically incorrect. Mozilla recognizes that and automatically moves it to body
section during page loading. One more disadvantage is you can't register any scripts after {% webpush %}
. For example, I can't write that:
<head>
{% webpush %}
<script src="{% static 'core/js/custom.js' %}"></script>
</head>
custom.js
will be ignored and not loaded at all.
2) It's incorrect to mix script declarations and elements storing data in one place. Also this element is tightly coupled and used with {% webpush_button %}
tag, why not place it there? This is more appropriate place.
3) Having a div
for only storing value from server probably is not the best choice. Hidden input with data attributes will be enough, but if we use it in {% webpush_button %}
, why not use existing elements for that such as button itself?
The code works perfectly well on localhost. But implementing the same by using amazon s3 to serve static files brings up the following error in console.
Uncaught (in promise) DOMException: Failed to register a ServiceWorker: The origin of the provided scriptURL ('https://myapp-bucket.s3.amazonaws.com') does not match the current origin ('https://myapp.herokuapp.com').
The current release (version 0.3.0) requires pywebpush
1.6.0.
When sending a notification, exceptions of type WebPushException
are caught and their response field is investigated
django-webpush/webpush/utils.py
Line 50 in 09996c0
pywebpush
.
Consequence: sending a notification to non-existent endpoint triggers a crash.
pywebpush
should be updated.
Hi, I have installed the package and generated the needed keys. I subscribed myself to receive notifications with an account without issues up till then.
When I log to the django admin interface and try to send a message to test if it works I get the following error.
File "/home/socialapp/deepmetricsapps/NuevocentroShopping/lib/python3.5/site-packages/webpush/utils.py", line 71, in _process_subscription_info endpoint = subscription_data.pop("endpoint") KeyError: 'endpoint'
Is this package still working? or am I doing something wrong?
I am using Django 2.0+ with gunicorn and nginx as reverse proxy. I subscribed to the service using chrome 70+
When I try to use the third option (with fine grain control), the line from webpush import WebPushException, send_single_notification
is not working.
Was the option removed?
Pypi points to https://github.com/web-push-libs/pywebpush, not this repo. This means that attempting to pip install gives you the wrong version.
current endpoint URLField max length is 255. However, Microsoft is using endpoints with more than 400 characters.
Could you update it to be 500 characters?
Thank you
During subscribing I get this error:
TypeError: the JSON object must be str, not 'bytes'
This is because of this line in save_info
view:
post_data = json.loads(request.body)
After debugging I have found that request.body
is bytes object, not simple string.
To fix that we need to convert it to string:
post_data = json.loads(request.body.decode(encoding='utf-8'))
However I'm not sure, maybe it can be both string and bytes depending on different circumstances.
In this case we can explicitly check for a type before converting.
request_body = request.body
if isinstance(request_body, bytes):
request_body = request_body.decode(encoding='utf-8')
post_data = json.loads(request.body)
But it would be better to find the reason why request.body
can be a bytes
object.
Some details: I use Python 3.5.2 and Django 1.9.5 in my project. Error happens in both Mozilla Firefox 49.0.1 and Chrome 53.0.2785.143 m browsers (these are the latest versions at the moment).
I tested it with the latest extension's code.
As a current workaround I overrided save_info
view and applied this fix and also overrided save_webpush_info
url, pointed it to custom view and placed it above extensions's urls:
url(r'^webpush/', include('webpush.urls')),
Does anyone know why the save_information
may return HTTP 400?
latest version subscribe button do not shows
'WebPushException' object has no attribute 'response'
When page initially loaded, subscribe
button is shown regardless of user already subscribed or not, This is not user friendly interface.
At least we need to check if user already subscribed and show some information about that (for example display "Unsubscribe" button instead).
Setting Up Web Push Notification for chrome is critical. Need to get Google Cloud messaging API key and set up through settings.
Must need to document them so that developer can set up easily.
Use a local ip address instead of a ngrok?
Hi thanks for the great work.
Can I dispense with ngrok?
I was asking how I could run the service via a local IP address
Eg on an internal network
router 10.10.1.1
// me : https://10.10.1.2
//pc2: 10.10.1.3
I want to communicate this way
iam use https from django ssl
but not working
thanks.
You can't pass extra= anything when raising WebPushException.
In django-webpush utils.py:
utils.py:22:raise WebPushException("Push failed.", extra=errors)
utils.py:40:raise WebPushException("Push failed.", extra=errors)
but in pywebpush init.py:
class WebPushException(Exception):
pass
Hi, it is possible to send a notification when I save a new record in my model, I use the django admin, I have tried to use signal to send the notification but it returns the following error!
WebPushException () takes no keyword arguments.
send me the notification but it takes and throws the error
example code: i have models name News
@receiver(post_save, sender=News)
def send_new_message_notification(sender, created, **kwargs):
message = kwargs['instance']
if created:
try:
obj = User.objects.get(pk=message.author.pk)
except sender.DoesNotExist:
pass
payload = {"head": "Welcome!", "body": message.title}
send_user_notification(user=obj, payload=payload, ttl=1000)
any help i will appreciate it
thank
I used the Fix from chris54
But now i got a 403 from Google
WebPushException at /admin/webpush/pushinformation/
I try to use the admin comand "Send test message"
There is missing a public method to send a notification to a single subcription.
Why it is needed?
Another problem with sending a notification to all user devices is when sending failed the loop is interrupted. That's why I would like to have better control over the process.
How to subscribe every user automatically without clicking the subscribe button and need to disable the button
So Chrome uses a different approach for getting user permission. Also, some different configuration is needed for sending push notification to android device. Need to find out that and open new issues about each task
When I click on subscribe button, server response is 400 due to missing 'p256dh' and 'auth' values(SubscriptionInfo table).
subscription_form.errors
>> {'p256dh': [u'This field is required.'], 'auth': [u'This field is required.']}
Where should i provide values for these fields ?
Both JS files:
serviceworker.js
webpush.js
should be loaded from main app static/js rather then django_webpush app,
because they need to be customized.
A user can include them like jquery file or so. (just extend readme.md)
I am having errors to runserver on django 1.9.7:
"INSTALLED_APPS." % (module, name)
RuntimeError: Model class django.contrib.contenttypes.models.ContentType doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
Performing system checks...
It seems that django version doesn't play well with import on init.py. Once I move the functions to utils.py everything seems fine.
When I use custom user model
I see webpush_button only with "Subscribe to notifications" when I subscribed
I can receive notifications, but button's text does not change
i've tried below code to print the payload data but not working
if('serviceWorker' in navigator){
navigator.serviceWorker.addEventListener('message', function(event) {
consloe.log(event.data);
});
}
I try follow all steps in read.me but nothing not working.
So, what i need to do this work?
The ttl
value is seconds, not milliseconds.
Django 1.10 fails with an "Apps are not ready" error when trying to load webpush because it's trying to load its models in __init__.py
but models haven't been loaded yet. The project should probably be restructured so it either uses lazy loading or doesn't load anything in __init__.py
.
Need to add test for everything so we dont get regression in future. also make it run into any CI
I am running Django version 1.6.7 but after adding webpush
to INSTALLED_APPS
I get ImportError: No module named dj_datadogwebpush
error. How do I fix it?
Hi!
I've got a problem - some time after subscribing I can't send messages to subscibers anymore. It seems something has expired and I don't know if I'm doing something wrong.
I've found this: https://serviceworke.rs/push-subscription-management_service-worker_doc.html and the service worker included here doesn't seem to handle pushsubscriptionchange event.
Is there a way to make subscriptions persist longer? Or is it simply not implemented yet?
This error is shown after running pip install django-webpush
:
Sorry: TabError: inconsistent use of tabs and spaces in indentation (validators.py, line 14)
As I said in #16 in this comment maybe it will be better to have just basic functionality in JS and not force user to use specific UI because it's hard to cover all possible variations and nuances.
In this case user can build his own interface, but for subscribing / unsubscribing he just only needs to call one method. Also we can generate some events and changes in UI will be done by subscribing to these events. This way logic and presentation will become more separated from each other.
We still can have basic template with button and probably it will fit majority of users, but it can be easily overridden using Django template mechanism.
Hello, in the admin i can see all the PushInformations object been created, some with users and other without which i assume this is working ok. The Send test message
action when executed returns a Test sent successfully
, which is also ok, but no notification is receive.
I have checked that the route https://[domain]/webpush/webpush_serviceworker.js
exists.
Not sure where else i have to look to get my notification working.
thanks
Site can already contain manifest.json
file. For example if you use favicon generator it can be like this:
{
"name": "Project name",
"icons": [
{
"src": "\/static\/core\/images\/favicons\/android-chrome-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": 0.75
},
{
"src": "\/static\/core\/images\/favicons\/android-chrome-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": 1
},
{
"src": "\/static\/core\/images\/favicons\/android-chrome-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": 1.5
},
{
"src": "\/static\/core\/images\/favicons\/android-chrome-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": 2
},
{
"src": "\/static\/core\/images\/favicons\/android-chrome-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": 3
},
{
"src": "\/static\/core\/images\/favicons\/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": 4
}
]
}
And it's already included in head
section in layout template along with other favicons related images:
<link rel="apple-touch-icon" sizes="57x57" href="{% static 'core/images/favicons/apple-touch-icon-57x57.png' %}">
<link rel="apple-touch-icon" sizes="60x60" href="{% static 'core/images/favicons/apple-touch-icon-60x60.png' %}">
<link rel="apple-touch-icon" sizes="72x72" href="{% static 'core/images/favicons/apple-touch-icon-72x72.png' %}">
<link rel="apple-touch-icon" sizes="76x76" href="{% static 'core/images/favicons/apple-touch-icon-76x76.png' %}">
<link rel="apple-touch-icon" sizes="114x114" href="{% static 'core/images/favicons/apple-touch-icon-114x114.png' %}">
<link rel="apple-touch-icon" sizes="120x120" href="{% static 'core/images/favicons/apple-touch-icon-120x120.png' %}">
<link rel="apple-touch-icon" sizes="144x144" href="{% static 'core/images/favicons/apple-touch-icon-144x144.png' %}">
<link rel="apple-touch-icon" sizes="152x152" href="{% static 'core/images/favicons/apple-touch-icon-152x152.png' %}">
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'core/images/favicons/apple-touch-icon-180x180.png' %}">
<link rel="icon" type="image/png" href="{% static 'core/images/favicons/favicon-32x32.png' %}" sizes="32x32">
<link rel="icon" type="image/png" href="{% static 'core/images/favicons/android-chrome-192x192.png' %}" sizes="192x192">
<link rel="icon" type="image/png" href="{% static 'core/images/favicons/favicon-96x96.png' %}" sizes="96x96">
<link rel="icon" type="image/png" href="{% static 'core/images/favicons/favicon-16x16.png' %}" sizes="16x16">
<!-- Manifest declaration begin -->
<link rel="manifest" href="{% static 'core/images/favicons/manifest.json' %}">
<!-- Manifest declaration end -->
<link rel="mask-icon" href="{% static 'core/images/favicons/safari-pinned-tab.svg' %}" color="#5bbad5">
<link rel="shortcut icon" href="{% static 'core/images/favicons/favicon.ico' %}">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-TileImage" content="{% static 'core/images/favicons/mstile-144x144.png' %}">
<meta name="msapplication-config" content="{% static 'core/images/favicons/browserconfig.xml' %}">
<meta name="theme-color" content="#ffffff">
If I include {% webpush %}
after favicons, it's ignored and I get the error about missing gcm_sender_id
which is needed for Chrome. If I placed it above favicons section - it works, but seems like only first manifest is loaded (site / app can have only one manifest.json
), further declarations are ignored so favicons will not work correctly.
Probably the order in template doesn't always matter (the order of loading by browser does), but anyways two manifest.json
declarations can cause conflict.
As a current workaround, I overrided webpush.html
template, removed manifest declaration from there and added gcm_sender_id
to existing manifest.json
.
I think we need an option to use existing manifest.json
instead of creating new one.
Ive found that you have a Group table which can be appended to with a group name. However there is no post method or view for adding a group. Sure it can be done manually. Also, if we have two entries one for a user who is authenticated and the same user being in a group. The send_group_notification sends two notifications. One for the specific user and another for the group which also goes to the same user. This is not correct as you would only want one notification to be sent. This is happening here in save_info method of webpush views.py
if request.user.is_authenticated or group_name:
# Save the subscription info with subscription data
# as the subscription data is a dictionary and its valid
subscription = subscription_form.get_or_save()
web_push_form.save_or_delete(
subscription=subscription, **user=request.user,**
status_type=status_type, group_name=group_name)
As both group and user information is sent while it should be exclusive one or the other.
The documentation for group creation is sparse and not clear.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.