-
Notifications
You must be signed in to change notification settings - Fork 40
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
[API] Added REST API for Notifications #48
Conversation
129921a
to
32559b9
Compare
openwisp_notifications/api/views.py
Outdated
notification_id = uuid.UUID(notification_id) | ||
notification = queryset.get(id=notification_id) | ||
except ValueError: | ||
return Response(status=status.HTTP_400_BAD_REQUEST) |
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.
@pandafy will it not be nice for us to give users some more information as to why their response didn't go through? It this case; it was caused by invalid notification_id
openwisp_notifications/api/views.py
Outdated
except ValueError: | ||
return Response(status=status.HTTP_400_BAD_REQUEST) | ||
except Notification.DoesNotExist: | ||
return Response(status=status.HTTP_404_NOT_FOUND) |
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.
Same here
02cf1f8
to
dcd0868
Compare
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.
Great work @pandafy 👍
But I think instead of having a mark_read patch
api, we could make this a details api for a specific notification. remember from the js widget, we should be able to read a notification. so replacing this with a get API for a specific notification will ease that work as getting a specific notification from the api will mark it as read.
Also, I think we should have an API to list all read notifications as well unread notifications, this could be use as a filter on the js widget.
7597720
to
f6a69c2
Compare
f6a69c2
to
e38a680
Compare
@NoumbissiValere Instead of adding them as individual endpoints, I have set them as filters using |
e38a680
to
fa6b5fc
Compare
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.
Great job @pandafy.
see some minor requests below
openwisp_notifications/api/urls.py
Outdated
url( | ||
r'^openwisp_notifications/notifications/$', | ||
views.list_notifications, | ||
name='api_list_notifications', |
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 think it will be good if we have this as list_notifications
openwisp_notifications/api/urls.py
Outdated
url( | ||
r'^openwisp_notifications/notifications/(?P<notification_id>[0-9A-Fa-f-]+)/$', | ||
views.read_notification, | ||
name='api_read_notifications', |
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.
same here read_notification
. since we are getting a single notification, keep away the s
openwisp_notifications/api/views.py
Outdated
queryset = Notification.objects.all() | ||
serializer_class = NotificationSerializer | ||
filter_backends = [DjangoFilterBackend] | ||
filterset_fields = ['unread'] |
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 don't think filter_backends
and filterset_fields
are needed in NotificationReadView
so they should be removed from the BaseNotificationView and send to the
NotificationListView`
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.
Great catch! 👍
64dab81
to
ff37070
Compare
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 progress! See my comments
README.rst
Outdated
|
||
.. code-block:: text | ||
|
||
GET /api/v1/openwisp_notifications/notifications/ |
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.
shorten openwisp_notifications/notifications/
to just notifications/
README.rst
Outdated
|
||
.. code-block:: text | ||
|
||
PATCH /api/v1/openwisp_notifications/notifications/{id}/ |
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.
same here
openwisp_notifications/api/urls.py
Outdated
app_name = 'openwisp_notifications' | ||
|
||
urlpatterns = [ | ||
url( |
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.
time to start using path
instead of url
, see the django docs
openwisp_notifications/api/urls.py
Outdated
name='list_notifications', | ||
), | ||
url( | ||
r'^openwisp_notifications/notifications/(?P<notification_id>[0-9A-Fa-f-]+)/$', |
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.
use path
with uuid
converter, eg: notifications/<uuid:pk>/
.
Use pk
instead of id
which is more generic.
|
||
urlpatterns = [ | ||
url( | ||
r'^api/v1/sample_notifications/notifications/$', |
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.
find a way to avoid repeating the url/path patterns, see how @atb00ker is doing it in the other modules he's working on
openwisp_notifications/api/views.py
Outdated
return self.list(request, *args, **kwargs) | ||
|
||
|
||
class NotificationReadView(BaseNotificationView): |
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 would call this NotificationDetailView
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 view does not provide details about a particular notification. It just mark them as read.
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 understand, I misread this.
Marking notifications as read does not need to return anything, because the consumer of the API is supposed to already have the list of notifications and we don't need to send back anything.
I would do the following:
GET /api/v1/notifications/
to get the list of notificationsGET /api/v1/notifications/<pk>/
to get the details of a specific notification, we add this just to make the API more completePOST /api/v1/notifications/read/
to flag all notifications as read, make it return just 200 OK and empty response body.
README.rst
Outdated
Authentication | ||
~~~~~~~~~~~~~~ | ||
|
||
The API authentication is based on session based authentication via REST framework. |
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.
Why isn't this as https://github.com/openwisp/openwisp-firmware-upgrader/#authentication
How to authenticate is explained in openwisp-users to avoid duplicating the information in every module.
When we'll have the comprehensive developer documentation we'll be linking a different section of the same documentation instead of a different repository, that will be the best, but for now, linking a different repo is the best option we have (duplicating the info in all the modules is unmaintainable for us right now).
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 have used session based authentication as in openwisp-ipam. I didn't thought it would be necessary to use use token based authentication.
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.
openwisp-ipam is not up to date, see openwisp/openwisp-ipam#33
Base your work by following openwisp-firmware-upgrader, which is up to date.
And yes, please add support for bearer authentication, we want to make sure the API can be used also outside of django easily. Beware of this bug in openwisp-users: openwisp/openwisp-users#126 @atb00ker should fix that soon, coordinate with him if you have any issue.
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.
@pandafy openwisp/openwisp-firmware-upgrader#85 please use this to avoid openwisp/openwisp-users#126
README.rst
Outdated
Browsable web interface | ||
~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
.. image:: docs/images/api-ui.png |
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.
great to see you added screenshots, we'll have to update them when the URLs are changed as requested
openwisp_notifications/api/views.py
Outdated
return self.list(request, *args, **kwargs) | ||
|
||
|
||
class NotificationReadView(BaseNotificationView): |
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 understand, I misread this.
Marking notifications as read does not need to return anything, because the consumer of the API is supposed to already have the list of notifications and we don't need to send back anything.
I would do the following:
GET /api/v1/notifications/
to get the list of notificationsGET /api/v1/notifications/<pk>/
to get the details of a specific notification, we add this just to make the API more completePOST /api/v1/notifications/read/
to flag all notifications as read, make it return just 200 OK and empty response body.
ff37070
to
10e1ff7
Compare
6892050
to
78dd814
Compare
6a85043
to
1bbd411
Compare
1bbd411
to
b506c0d
Compare
b506c0d
to
781ffb5
Compare
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.
Did a local test and it looks good (haven't been able to create test notifications in the dev env quicky though).
See below for further improvements and we'll be ready to move on.
README.rst
Outdated
Live documentation | ||
~~~~~~~~~~~~~~~~~~ | ||
|
||
.. image:: docs/images/api-docs.png |
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 forgot to mention that relative paths don't work when the README is published elsewhere (eg: pypi).
with @atb00ker we had the same issue before.
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.
Yeah, using the complete links for now https://github.com/......api-docs.png should fix the issue! 😄
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.
Thanks, I was not aware of this. 😄
openwisp_notifications/api/views.py
Outdated
class BaseNotificationView(GenericAPIView): | ||
model = Notification | ||
authentication_classes = [BearerAuthentication, SessionAuthentication] | ||
permission_classes = [DjangoModelPermissions] |
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.
spotted, I think we can simplify this and just use IsAuthenticated
, because we want all users to be able to access their notifications if this module is enabled, regardless of the permissions (django model permissions are not really useful in this case). Using IsAuthenticated
will result in less load on the server when retrieving notifications (permission checks are not free).
NOT_FOUND_ERROR = ErrorDetail(string='Not found.', code='not_found') | ||
|
||
|
||
class TestNotificationApi(TestCase, TestOrganizationMixin, AuthenticationMixin): |
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.
can you add a test which does the following:
- given 2 users, Joe and Karen
- ensure Joe cannot GET, PATCH or DELETE a notification ID that is assigned to Karen
Given the current code, it looks to me that this should work, but someone in the future may inadvertently change the code and break it.
Better safe than sorry.
README.rst
Outdated
urlpatterns = [ | ||
path('admin/', admin.site.urls), | ||
path('api/v1/', include(('openwisp_users.api.urls', 'users'), namespace='users')), | ||
path('',include('openwisp_notifications.urls', namespace='openwisp_notifications')), |
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.
missing space before include
d65d099
to
0784a8f
Compare
0784a8f
to
3e62713
Compare
Added API endpoint for notifications: List, retrieve, delete and flag notifications as read.
3e62713
to
47b0f4f
Compare
self.assertEqual(response.status_code, 404) | ||
self.assertDictEqual(response.data, {'detail': NOT_FOUND_ERROR}) | ||
# Check Karen's notification is still unread | ||
n = Notification.objects.first() |
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.
did you know you can use n.refresh_from_db()
?
Bumps openwisp-utils to version >=0.5
Implements API for listing marking notification as read
Closes #3