From 8e6802f8a9603547147475c2acebbf627e23933c Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Tue, 31 Mar 2026 18:01:59 -0400 Subject: [PATCH] [tasks] Revert webhook for Todoist --- vrobbler/apps/tasks/webhooks.py | 191 +++++++++++++++++--------------- 1 file changed, 99 insertions(+), 92 deletions(-) diff --git a/vrobbler/apps/tasks/webhooks.py b/vrobbler/apps/tasks/webhooks.py index 2378e86..ac3af40 100644 --- a/vrobbler/apps/tasks/webhooks.py +++ b/vrobbler/apps/tasks/webhooks.py @@ -1,10 +1,13 @@ import json import logging +from django.views.decorators.csrf import csrf_exempt 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.response import Response -from scrobbles.views import WebhookView +from rest_framework.views import APIView from scrobbles.scrobblers import ( emacs_scrobble_task, emacs_scrobble_update_task, @@ -15,104 +18,108 @@ from scrobbles.scrobblers import ( logger = logging.getLogger(__name__) -class TodoistWebhookView(WebhookView): - def post(self, request): - post_data = request.data - self.logger.info( - "[todoist_webhook] called", - extra={"post_data": post_data}, - ) - todoist_task = {} - todoist_note = {} - 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_type == "note" - new_labels = event_data.get("labels", []) - old_labels = ( - post_data.get("event_data_extra", {}).get("old_item", {}).get("labels", []) - ) - is_updated = todoist_event in ["updated"] - is_added = todoist_event in ["added"] +@csrf_exempt +@permission_classes([IsAuthenticated]) +def todoist_webhook(request): + post_data = request.data + logger.info( + "[todoist_webhook] called", + extra={"post_data": post_data}, + ) + todoist_task = {} + todoist_note = {} + 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" + 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"] - task_started = "inprogress" in new_labels and "inprogress" not in old_labels - task_stopped = "inprogress" not in new_labels and "inprogress" in old_labels + task_started = "inprogress" in new_labels and "inprogress" not in old_labels + task_stopped = "inprogress" not in new_labels and "inprogress" in old_labels - if is_item_type and is_updated and (task_started or task_stopped): - todoist_task = { - "todoist_id": event_data.get("id"), - "todoist_label_list": event_data.get("labels"), + if is_item_type and is_updated and (task_started or task_stopped): + todoist_task = { + "todoist_id": event_data.get("id"), + "todoist_label_list": event_data.get("labels"), + "todoist_type": todoist_type, + "todoist_event": todoist_event, + "updated_at": event_data.get("updated_at"), + "todoist_project_id": event_data.get("project_id"), + "description": event_data.get("content"), + "details": event_data.get("description"), + } + if is_note_type and is_added: + task_data = event_data.get("item", {}) + todoist_note = { + "task_id": event_data.get("item_id"), + "todoist_id": event_data.get("id"), + "todoist_label_list": task_data.get("labels"), + "todoist_type": todoist_type, + "todoist_event": todoist_event, + "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), + } + + if (is_added and not todoist_note) or (is_updated and not todoist_task): + logger.info( + "[todoist_webhook] ignoring wrong todoist type, event or labels", + extra={ "todoist_type": todoist_type, "todoist_event": todoist_event, - "updated_at": event_data.get("updated_at"), - "todoist_project_id": event_data.get("project_id"), - "description": event_data.get("content"), - "details": event_data.get("description"), - } - if is_note_type and is_added: - task_data = event_data.get("item", {}) - todoist_note = { - "task_id": event_data.get("item_id"), - "todoist_id": event_data.get("id"), - "todoist_label_list": task_data.get("labels"), - "todoist_type": todoist_type, - "todoist_event": todoist_event, - "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 - ), - } - - if (is_added and not todoist_note) or (is_updated and not todoist_task): - self.logger.info( - "[todoist_webhook] ignoring wrong todoist type, event or labels", - extra={ - "todoist_type": todoist_type, - "todoist_event": todoist_event, - "task_started": task_started, - "task_stopped": task_stopped, - "new_labels": new_labels, - "old_labels": old_labels, - }, - ) - 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( - todoist_task, - user_profile.user_id, - stopped=task_stopped, - user_context_list=user_profile.task_context_tags, - ) - - if todoist_note: - scrobble = todoist_scrobble_update_task(todoist_note, user_profile.user_id) - - if not scrobble: - self.logger.info( - "[todoist_webhook] finished with no note or task found", - extra={"scrobble_id": None}, - ) - return Response( - {"error": "No scrobble found to be updated"}, - status=status.HTTP_304_NOT_MODIFIED, - ) - - self.logger.info( - "[todoist_webhook] finished", - extra={"scrobble_id": scrobble.id}, + "task_started": task_started, + "task_stopped": task_stopped, + "new_labels": new_labels, + "old_labels": old_labels, + }, ) - return Response({"scrobble_id": scrobble.id}, status=status.HTTP_200_OK) + 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( + todoist_task, + user_profile.user_id, + stopped=task_stopped, + user_context_list=user_profile.task_context_tags, + ) + + if todoist_note: + scrobble = todoist_scrobble_update_task(todoist_note, user_profile.user_id) + + if not scrobble: + logger.info( + "[todoist_webhook] finished with no note or task found", + extra={"scrobble_id": None}, + ) + return Response( + {"error": "No scrobble found to be updated"}, + status=status.HTTP_304_NOT_MODIFIED, + ) + + logger.info( + "[todoist_webhook] finished", + extra={"scrobble_id": scrobble.id}, + ) + return Response({"scrobble_id": scrobble.id}, status=status.HTTP_200_OK) -class EmacsWebhookView(WebhookView): +class EmacsWebhookView(APIView): + @property + def logger(self): + return logger + def post(self, request): try: post_data = json.loads(request.data)