[tasks] Clean up todoist scrobbling
This commit is contained in:
@ -1,8 +1,7 @@
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django.urls import reverse_lazy
|
||||
from django.views.generic import FormView
|
||||
|
||||
from profiles.forms import UserProfileForm
|
||||
|
||||
|
||||
@ -27,4 +26,5 @@ class ProfileFormView(LoginRequiredMixin, FormView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["user_id"] = self.request.user.id
|
||||
context["profile"] = self.request.user.profile
|
||||
return context
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from django.urls import path
|
||||
from scrobbles import views
|
||||
from tasks.webhooks import EmacsWebhookView, todoist_webhook
|
||||
from tasks.webhooks import EmacsWebhookView, TodoistWebhookView
|
||||
|
||||
app_name = "scrobbles"
|
||||
|
||||
@ -82,7 +82,7 @@ urlpatterns = [
|
||||
views.MopidyWebhookView.as_view(),
|
||||
name="mopidy-webhook",
|
||||
),
|
||||
path("webhook/todoist/", todoist_webhook, name="todoist-webhook"),
|
||||
path("webhook/todoist/", TodoistWebhookView.as_view(), name="todoist-webhook"),
|
||||
path("webhook/emacs/", EmacsWebhookView.as_view(), name="emacs_webhook"),
|
||||
path("export/", views.export, name="export"),
|
||||
path(
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.utils import timezone
|
||||
from profiles.models import UserProfile
|
||||
from rest_framework.decorators import permission_classes
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework import status
|
||||
from rest_framework.authentication import BaseAuthentication
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
from rest_framework.permissions import BasePermission
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from scrobbles.scrobblers import (
|
||||
@ -18,11 +19,53 @@ from scrobbles.scrobblers import (
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@permission_classes([IsAuthenticated])
|
||||
def todoist_webhook(request):
|
||||
class TodoistTokenAuthentication(BaseAuthentication):
|
||||
keyword = "Bearer"
|
||||
|
||||
def authenticate(self, request):
|
||||
auth_header = request.META.get("HTTP_AUTHORIZATION", "")
|
||||
|
||||
if not auth_header:
|
||||
return None
|
||||
|
||||
parts = auth_header.split()
|
||||
|
||||
if len(parts) != 2 or parts[0] != self.keyword:
|
||||
return None
|
||||
|
||||
token = parts[1]
|
||||
|
||||
profile = UserProfile.objects.filter(todoist_auth_key=token).first()
|
||||
|
||||
if not profile:
|
||||
raise AuthenticationFailed("Invalid token")
|
||||
|
||||
if not profile.user:
|
||||
raise AuthenticationFailed("No user associated with token")
|
||||
|
||||
return (profile.user, profile)
|
||||
|
||||
|
||||
class IsAuthenticatedForTodoist(BasePermission):
|
||||
def has_permission(self, request):
|
||||
return (
|
||||
hasattr(request, "user") and request.user and request.user.is_authenticated
|
||||
)
|
||||
|
||||
|
||||
class TodoistWebhookView(APIView):
|
||||
authentication_classes = [TodoistTokenAuthentication]
|
||||
permission_classes = [IsAuthenticatedForTodoist]
|
||||
|
||||
@property
|
||||
def logger(self):
|
||||
return logger
|
||||
|
||||
def post(self, request):
|
||||
user_profile = request.auth
|
||||
|
||||
post_data = request.data
|
||||
logger.info(
|
||||
self.logger.info(
|
||||
"[todoist_webhook] called",
|
||||
extra={"post_data": post_data},
|
||||
)
|
||||
@ -31,12 +74,11 @@ def todoist_webhook(request):
|
||||
todoist_type, todoist_event = post_data.get("event_name").split(":")
|
||||
event_data = post_data.get("event_data", {})
|
||||
is_item_type = todoist_type == "item"
|
||||
is_note_type = todoist_tyllll = "note"
|
||||
is_note_type = todoist_type == "note"
|
||||
new_labels = event_data.get("labels", [])
|
||||
old_labels = (
|
||||
post_data.get("event_data_extra", {}).get("old_item", {}).get("labels", [])
|
||||
)
|
||||
# TODO Don't hard code status strings in here
|
||||
is_updated = todoist_event in ["updated"]
|
||||
is_added = todoist_event in ["added"]
|
||||
|
||||
@ -65,11 +107,13 @@ def todoist_webhook(request):
|
||||
"updated_at": task_data.get("updated_at"),
|
||||
"details": task_data.get("description"),
|
||||
"notes": event_data.get("content"),
|
||||
"is_deleted": (True if event_data.get("is_deleted") == "true" else False),
|
||||
"is_deleted": (
|
||||
True if event_data.get("is_deleted") == "true" else False
|
||||
),
|
||||
}
|
||||
|
||||
if (is_added and not todoist_note) or (is_updated and not todoist_task):
|
||||
logger.info(
|
||||
self.logger.info(
|
||||
"[todoist_webhook] ignoring wrong todoist type, event or labels",
|
||||
extra={
|
||||
"todoist_type": todoist_type,
|
||||
@ -82,10 +126,6 @@ def todoist_webhook(request):
|
||||
)
|
||||
return Response({}, status=status.HTTP_304_NOT_MODIFIED)
|
||||
|
||||
user_profile = UserProfile.objects.filter(
|
||||
todoist_user_id=post_data.get("user_id", None)
|
||||
).first()
|
||||
|
||||
scrobble = None
|
||||
if todoist_task:
|
||||
scrobble = todoist_scrobble_task(
|
||||
@ -99,7 +139,7 @@ def todoist_webhook(request):
|
||||
scrobble = todoist_scrobble_update_task(todoist_note, user_profile.user_id)
|
||||
|
||||
if not scrobble:
|
||||
logger.info(
|
||||
self.logger.info(
|
||||
"[todoist_webhook] finished with no note or task found",
|
||||
extra={"scrobble_id": None},
|
||||
)
|
||||
@ -108,7 +148,7 @@ def todoist_webhook(request):
|
||||
status=status.HTTP_304_NOT_MODIFIED,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
self.logger.info(
|
||||
"[todoist_webhook] finished",
|
||||
extra={"scrobble_id": scrobble.id},
|
||||
)
|
||||
|
||||
@ -138,4 +138,15 @@
|
||||
{% endfor %}
|
||||
<input type="submit" value="Save">
|
||||
</form>
|
||||
|
||||
<div class="widget-links" style="margin-top: 16px;">
|
||||
<strong>Todoist Integration:</strong>
|
||||
{% if profile.todoist_auth_key %}
|
||||
<p>Connected to Todoist</p>
|
||||
<a href="{% url 'tasks:task_todoist_auth' %}" class="btn btn-sm btn-secondary">Reconnect to Todoist</a>
|
||||
{% else %}
|
||||
<p>Not connected</p>
|
||||
<a href="{% url 'tasks:task_todoist_auth' %}" class="btn btn-sm btn-primary">Connect to Todoist</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user