From 454461d4840a949da4dfad5115d7e971bd1fd94a Mon Sep 17 00:00:00 2001
From: James Graham <J.Graham@software.ac.uk>
Date: Wed, 20 Feb 2019 14:17:14 +0000
Subject: [PATCH] Allow Application API tokens to be revoked by their owner

---
 .../applications/application/detail.html      | 23 +++++++++++++++++++
 applications/urls.py                          |  4 ++++
 applications/views.py                         | 18 ++++++++++++++-
 pedasi/common/__init__.py                     |  0
 profiles/models.py                            |  7 ++++++
 5 files changed, 51 insertions(+), 1 deletion(-)
 delete mode 100644 pedasi/common/__init__.py

diff --git a/applications/templates/applications/application/detail.html b/applications/templates/applications/application/detail.html
index cdeb12b..36f7b5f 100644
--- a/applications/templates/applications/application/detail.html
+++ b/applications/templates/applications/application/detail.html
@@ -1,6 +1,10 @@
 {% extends "base.html" %}
 {% load bootstrap4 %}
 
+{% block extra_head %}
+    <script src="https://cdn.jsdelivr.net/npm/js-cookie@2.2.0/src/js.cookie.min.js"></script>
+{% endblock %}
+
 {% block content %}
     <nav aria-label="breadcrumb">
         <ol class="breadcrumb">
@@ -64,8 +68,27 @@
                     <td>
                         <span id="spanApiToken">
                             {% if application.proxy_user.auth_token %}
+                                <script type="application/javascript">
+                                    function revokeToken() {
+                                        $.ajax({
+                                            dataType: "json",
+                                            url: "{% url 'applications:token' pk=application.pk %}",
+                                            method: "DELETE",
+                                            headers: {
+                                                "X-CSRFToken": Cookies.get("csrftoken")
+                                            },
+                                            data: null,
+                                            success: function (data) {
+                                                $('#spanApiToken').text("");
+                                            }
+                                        });
+                                    }
+                                </script>
+
                                 {{ application.proxy_user.auth_token }}
 
+                                <button onclick="revokeToken();" class="btn btn-danger" role="button">Revoke API Token</button>
+
                             {% else %}
                                 <script type="application/javascript">
                                     function getToken() {
diff --git a/applications/urls.py b/applications/urls.py
index ae74341..0d4ad19 100644
--- a/applications/urls.py
+++ b/applications/urls.py
@@ -29,6 +29,10 @@ urlpatterns = [
          views.ApplicationGetTokenView.as_view(),
          name='token'),
 
+    path('<int:pk>/token',
+         views.ApplicationGetTokenView.as_view(),
+         name='token'),
+
     path('<int:pk>/manage-access',
          views.ApplicationManageAccessView.as_view(),
          name='application.manage-access'),
diff --git a/applications/views.py b/applications/views.py
index 8256596..e9c6a01 100644
--- a/applications/views.py
+++ b/applications/views.py
@@ -98,7 +98,7 @@ class ApplicationGetTokenView(OwnerPermissionMixin, DetailView):
 
     def render_to_response(self, context, **response_kwargs):
         """
-        Get an existing API Token or create a new one for the currently authenticated user.
+        Get an existing API Token or create a new one for the requested :class:`Application`.
 
         :return: JSON containing Token key
         """
@@ -112,3 +112,19 @@ class ApplicationGetTokenView(OwnerPermissionMixin, DetailView):
                 }
             }
         })
+
+    def delete(self, request, *args, **kwargs):
+        """
+        Revoke an API Token for the requested :class:`Application`.
+
+        :return: JSON containing Token key
+        """
+        self.object = self.get_object()
+        self.object.proxy_user.revoke_auth_token()
+
+        return JsonResponse({
+            'status': 'success',
+            'data': {
+                'token': None,
+            }
+        })
diff --git a/pedasi/common/__init__.py b/pedasi/common/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/profiles/models.py b/profiles/models.py
index 1ef5590..738fa71 100644
--- a/profiles/models.py
+++ b/profiles/models.py
@@ -28,3 +28,10 @@ class User(AbstractUser):
         """
         token, created = Token.objects.get_or_create(user=self)
         return token
+
+    def revoke_auth_token(self):
+        """
+        Revoke and API auth token for this user.
+        """
+        self.auth_token.delete()
+
-- 
GitLab