Skip to content

Commit

Permalink
integrations: Add ClickUp integration.
Browse files Browse the repository at this point in the history
Creates an incoming webhook integration for ClickUp. The main
use case is getting notifications when new ClickUp items such as task, list, folder, space, goals are created, updated or deleted.

Fixes zulip#26529.
  • Loading branch information
PieterCK committed Apr 2, 2024
1 parent c44c84b commit e4883b8
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 218 deletions.
1 change: 1 addition & 0 deletions zerver/lib/integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.utils.translation import gettext_lazy
from django_stubs_ext import StrPromise
from typing_extensions import TypeAlias

from zerver.lib.storage import static_path

"""This module declares all of the (documented) integrations available
Expand Down
45 changes: 45 additions & 0 deletions zerver/webhooks/clickup/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from enum import Enum
from typing import List


class ConstantVariable(Enum):
@classmethod
def as_list(cls) -> List[str]:
return [item.value for item in cls]


class EventItemType(ConstantVariable):
TASK: str = "task"
LIST: str = "list"
FOLDER: str = "folder"
GOAL: str = "goal"
SPACE: str = "space"


class EventAcion(ConstantVariable):
CREATED: str = "Created"
UPDATED: str = "Updated"
DELETED: str = "Deleted"


class SimpleFields(ConstantVariable):
# Events with identical payload format
PRIORITY: str = "priority"
STATUS: str = "status"


class SpecialFields(ConstantVariable):
# Event with unique payload
NAME: str = "name"
ASSIGNEE: str = "assignee_add"
COMMENT: str = "comment"
DUE_DATE: str = "due_date"
MOVED: str = "section_moved"
TIME_ESTIMATE: str = "time_estimate"
TIME_SPENT: str = "time_spent"


class SpammyFields(ConstantVariable):
TAG: str = "tag"
TAG_REMOVED: str = "tag_removed"
UNASSIGN: str = "assignee_rem"
16 changes: 15 additions & 1 deletion zerver/webhooks/clickup/api_endpoints.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import re
from typing import Any, Dict
from urllib.parse import urljoin

import requests
from urllib.parse import urljoin

from zerver.lib.outgoing_http import OutgoingSession
from zerver.webhooks.clickup import EventItemType


class Error(Exception):
Expand All @@ -22,7 +25,18 @@ def __init__(self, **kwargs: Any) -> None:
super().__init__(role="clickup", timeout=5, **kwargs)


def verify_url_path(path: str) -> bool:
parts = path.split("/")
if len(parts) < 2 or parts[0] not in EventItemType.as_list() or parts[1] == "":
return False
pattern = r"^[a-zA-Z0-9_-]+$"
match = re.match(pattern, parts[1])
return match is not None and match.group() == parts[1]


def make_clickup_request(path: str, api_key: str) -> Dict[str, Any]:
if verify_url_path(path) is False:
raise BadRequestError("Invalid path")
headers: Dict[str, str] = {
"Content-Type": "application/json",
"Authorization": api_key,
Expand Down
24 changes: 12 additions & 12 deletions zerver/webhooks/clickup/callback_fixtures/get_folder.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"id": "457",
"name": "Lord Foldemort",
"orderindex": 0,
"override_statuses": false,
"hidden": false,
"space": {
"id": "789",
"name": "Space Name",
"access": true
},
"task_count": "0",
"lists": []
"id": "457",
"name": "Lord Foldemort",
"orderindex": 0,
"override_statuses": false,
"hidden": false,
"space": {
"id": "789",
"name": "Space Name",
"access": true
},
"task_count": "0",
"lists": []
}
60 changes: 30 additions & 30 deletions zerver/webhooks/clickup/callback_fixtures/get_goal.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
{
"goal": {
"id": "e53a033c-900e-462d-a849-4a216b06d930",
"name": "hat-trick",
"team_id": "512",
"date_created": "1568044355026",
"start_date": null,
"due_date": "1568036964079",
"description": "Updated Goal Description",
"private": false,
"archived": false,
"creator": 183,
"color": "#32a852",
"pretty_id": "6",
"multiple_owners": true,
"folder_id": null,
"members": [],
"owners": [
{
"id": 182,
"username": "Pieter CK",
"email": "[email protected]",
"color": "#7b68ee",
"initials": "PK",
"profilePicture": "https://attachments-public.clickup.com/profilePictures/182_abc.jpg"
}
],
"key_results": [],
"percent_completed": 0,
"history": [],
"pretty_url": "https://app.clickup.com/512/goals/6"
"id": "e53a033c-900e-462d-a849-4a216b06d930",
"name": "hat-trick",
"team_id": "512",
"date_created": "1568044355026",
"start_date": null,
"due_date": "1568036964079",
"description": "Updated Goal Description",
"private": false,
"archived": false,
"creator": 183,
"color": "#32a852",
"pretty_id": "6",
"multiple_owners": true,
"folder_id": null,
"members": [],
"owners": [
{
"id": 182,
"username": "Pieter CK",
"email": "[email protected]",
"color": "#7b68ee",
"initials": "PK",
"profilePicture": "https://attachments-public.clickup.com/profilePictures/182_abc.jpg"
}
],
"key_results": [],
"percent_completed": 0,
"history": [],
"pretty_url": "https://app.clickup.com/512/goals/6"
}
}
}
50 changes: 25 additions & 25 deletions zerver/webhooks/clickup/callback_fixtures/get_list.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,46 @@
"orderindex": 1,
"content": "Updated List Content",
"status": {
"status": "red",
"color": "#e50000",
"hide_label": true
"status": "red",
"color": "#e50000",
"hide_label": true
},
"priority": {
"priority": "high",
"color": "#f50000"
"priority": "high",
"color": "#f50000"
},
"assignee": null,
"due_date": "1567780450202",
"due_date_time": true,
"start_date": null,
"start_date_time": null,
"folder": {
"id": "456",
"name": "Folder Name",
"hidden": false,
"access": true
"id": "456",
"name": "Folder Name",
"hidden": false,
"access": true
},
"space": {
"id": "789",
"name": "Space Name",
"access": true
"id": "789",
"name": "Space Name",
"access": true
},
"inbound_address": "add.task.124.ac725f.31518a6a-05bb-4997-92a6-1dcfe2f527ca@tasks.clickup.com",
"archived": false,
"override_statuses": false,
"statuses": [
{
"status": "to do",
"orderindex": 0,
"color": "#d3d3d3",
"type": "open"
},
{
"status": "complete",
"orderindex": 1,
"color": "#6bc950",
"type": "closed"
}
{
"status": "to do",
"orderindex": 0,
"color": "#d3d3d3",
"type": "open"
},
{
"status": "complete",
"orderindex": 1,
"color": "#6bc950",
"type": "closed"
}
],
"permission_level": "create"
}
}
86 changes: 43 additions & 43 deletions zerver/webhooks/clickup/callback_fixtures/get_space.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,50 @@
"name": "the Milky Way",
"private": false,
"statuses": [
{
"status": "to do",
"type": "open",
"orderindex": 0,
"color": "#d3d3d3"
},
{
"status": "complete",
"type": "closed",
"orderindex": 1,
"color": "#6bc950"
}
{
"status": "to do",
"type": "open",
"orderindex": 0,
"color": "#d3d3d3"
},
{
"status": "complete",
"type": "closed",
"orderindex": 1,
"color": "#6bc950"
}
],
"multiple_assignees": false,
"features": {
"due_dates": {
"enabled": false,
"start_date": false,
"remap_due_dates": false,
"remap_closed_due_date": false
},
"time_tracking": {
"enabled": false
},
"tags": {
"enabled": false
},
"time_estimates": {
"enabled": false
},
"checklists": {
"enabled": true
},
"custom_fields": {
"enabled": true
},
"remap_dependencies": {
"enabled": false
},
"dependency_warning": {
"enabled": false
},
"portfolios": {
"enabled": false
}
"due_dates": {
"enabled": false,
"start_date": false,
"remap_due_dates": false,
"remap_closed_due_date": false
},
"time_tracking": {
"enabled": false
},
"tags": {
"enabled": false
},
"time_estimates": {
"enabled": false
},
"checklists": {
"enabled": true
},
"custom_fields": {
"enabled": true
},
"remap_dependencies": {
"enabled": false
},
"dependency_warning": {
"enabled": false
},
"portfolios": {
"enabled": false
}
}
}
}
Loading

0 comments on commit e4883b8

Please sign in to comment.