| from fastapi import FastAPI, Request |
| from pydantic import BaseModel |
| import requests |
| import logging |
| from datetime import datetime |
|
|
| |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') |
|
|
| app = FastAPI() |
|
|
| |
| CLICKUP_URL_BASE = "https://api.clickup.com/api/v2" |
|
|
| |
| WHATSAPP_URL = "https://7105.api.greenapi.com/waInstance7105210836/sendMessage/805b69f6c85d4e6caea0edaba692b889abecc9e6bb8b457e8f" |
|
|
| |
| ACCESS_TOKEN = "2144425825_36f2249dc27c5aca075ac5442b1bbcdf01c3a29b9e41b86bda46a6cf651acd0f" |
|
|
| |
| headers = { |
| "Authorization": ACCESS_TOKEN, |
| "Content-Type": "application/json" |
| } |
|
|
| |
| whatsapp_headers = { |
| "Content-Type": "application/json" |
| } |
|
|
| class TaskData(BaseModel): |
| task_name: str |
| task_type: str |
| campaign_name: str |
| platforms: list[str] |
| assignees: list[int] |
| due_date: int |
|
|
| @app.post("/singletask") |
| async def create_task(request: Request): |
| data = await request.json() |
| logging.info(f"Received task data: {data}") |
|
|
| |
| team = data.get('team', '') |
| task_type = data.get('taskType', '') |
| task_title = data.get('taskTitle', '') |
| assignees = data.get('assignees', '') |
| platforms = data.get('platforms', []) |
| deadline = data.get('deadline', '') |
| goal = data.get('goal', '') |
| description = data.get('description', '') |
| creative_type = data.get('creativeType', '') |
| ad_content = data.get('adContent', '') |
| posting_content = data.get('postingContent', '') |
| attachment_link = data.get('attachmentLink', '') |
| start_date = data.get('startDate', '') |
| end_date = data.get('endDate', '') |
|
|
| |
| print(f"Team: {team}") |
| print(f"Task Type: {task_type}") |
| print(f"Task Title: {task_title}") |
| print(f"Assignees: {assignees}") |
| print(f"Platforms: {platforms}") |
| print(f"Deadline: {deadline}") |
| print(f"Goal: {goal}") |
| print(f"Description: {description}") |
| print(f"Creative Type: {creative_type}") |
| print(f"Ad Content: {ad_content}") |
| print(f"Posting Content: {posting_content}") |
| print(f"Attachment Link: {attachment_link}") |
| print(f"Start Date: {start_date}") |
| print(f"End Date: {end_date}") |
|
|
|
|
| web_app_url = "https://script.google.com/macros/s/AKfycbzL6OVq4WNKb1mX0BWEtvxYNRKUdjmzp-gjCbhHOZa_y3N9XB9IF_RWZxlgB_Dx07Aw/exec" |
| params = { |
| "mode": "extended", |
| "taskType": task_type, |
| "company": team, |
| "assignees": ','.join(assignees) |
| } |
|
|
| response = requests.get(web_app_url, params=params) |
| try: |
| response_data = response.json() |
| except ValueError: |
| print("ERROR: Failed to decode JSON from web app response") |
| return {"error": "Invalid response from Google Apps Script"} |
|
|
| print(f"Web App Response: {response_data}") |
|
|
| list_id = response_data.get("listId") |
| print(f"List ID: {list_id}") |
|
|
| assignee_ids = response_data.get("assigneeIds", []) |
| print(f"Assignee IDs: {assignee_ids}") |
|
|
| assignee_numbers = response_data.get("assigneeNumbers", []) |
| manager_numbers = response_data.get("managerNumbers", []) |
|
|
| print(f"Assignee Numbers: {assignee_numbers}") |
| print(f"Manager Numbers: {manager_numbers}") |
| |
| |
| description_text = "" |
|
|
| task_type_lower = task_type.lower() |
|
|
| if task_type_lower == "strategy": |
| status = "to do" |
| description_text = description |
|
|
| elif task_type_lower == "content": |
| status = "backlog" |
| description_text = f"{goal.strip()}".strip() |
| if platforms: |
| description_text += "\n\nPlatforms: " + ", ".join(platforms) |
|
|
| elif task_type_lower == "creative": |
| status = "to do" |
| description_text = f"{creative_type.strip()}".strip() |
| if platforms: |
| description_text += "\n\nPlatforms: " + ", ".join(platforms) |
|
|
| elif task_type_lower == "ads": |
| status = "ready" |
| parts = [] |
| if ad_content: |
| parts.append(ad_content.strip()) |
| if attachment_link: |
| parts.append(f"Attachment: {attachment_link.strip()}") |
| if platforms: |
| parts.append("Platforms: " + ", ".join(platforms)) |
| description_text = "\n\n".join(parts) |
|
|
| elif task_type_lower == "posting": |
| status = "ready for posting" |
| parts = [] |
| if posting_content: |
| parts.append(posting_content.strip()) |
| if platforms: |
| parts.append("Platforms: " + ", ".join(platforms)) |
| if attachment_link: |
| parts.append(f"Attachment: {attachment_link.strip()}") |
| description_text = "\n\n".join(parts) |
|
|
| elif task_type_lower == "ads report": |
| status = "ready" |
| platforms_text = ", ".join(platforms) if platforms else "" |
| description_text = f"Prepare an ads report for {platforms_text}" |
| if start_date and end_date: |
| description_text += f" from {start_date} to {end_date}" |
|
|
| else: |
| return {"error": f"Unsupported task type: {task_type}"} |
| |
| |
| payload = { |
| "name": task_title, |
| "description": description_text, |
| "assignees": [int(uid) for uid in assignee_ids], |
| "status": status |
| } |
|
|
| |
| if deadline: |
| try: |
| due_timestamp = int(datetime.strptime(deadline, "%Y-%m-%d").timestamp() * 1000) |
| payload["due_date"] = due_timestamp |
| print(f"Due Date (timestamp): {due_timestamp}") |
| except ValueError: |
| print("Invalid deadline format. Skipping due_date.") |
|
|
| |
| create_url = f"{CLICKUP_URL_BASE}/list/{list_id}/task" |
| clickup_response = requests.post(create_url, headers=headers, json=payload) |
| clickup_data = clickup_response.json() |
| print(f"ClickUp Response: {clickup_response.status_code}, {clickup_data}") |
|
|
| |
| |
| |
|
|
| return {"status": "Task data received and parsed"} |
|
|
| |
| def get_task_name(task_id): |
| """Fetch task details from ClickUp API using task_id.""" |
| url = f"https://api.clickup.com/api/v2/task/{task_id}" |
| headers = { |
| "Authorization": ACCESS_TOKEN |
| } |
| |
| |
| response = requests.get(url, headers=headers) |
|
|
| |
| if response.status_code == 200: |
| |
| |
| task_name = response.json()["name"] |
| return task_name |
| else: |
| task_name = "Task name wasn't not found" |
| return task_name |
|
|
| def get_task_details(task_id): |
| url = f"https://api.clickup.com/api/v2/task/{task_id}" |
| headers = {"Authorization": ACCESS_TOKEN} |
| |
| response = requests.get(url, headers=headers) |
| |
| if response.status_code == 200: |
| task_data = response.json() |
| else: |
| print(f"Error: {response.status_code}, {response.text}") |
| task_data = "invalid data" |
|
|
| return task_data |
|
|
| @app.post("/updates") |
| async def task_update(request: Request): |
| data = await request.json() |
| logging.info(f"Received task update from ClickUp: {data}") |
|
|
| event_type = data.get("event") |
| task_id = data.get("task_id", "Unknown ID") |
| |
| |
| task_name = get_task_name(task_id) |
| task_link = f"https://app.clickup.com/t/{task_id}" |
|
|
| if event_type == "taskUpdated": |
| history_items = data.get("history_items", []) |
|
|
| for item in history_items: |
| if item.get("field") == "status": |
| after_status = item.get("after", {}).get("status") |
| action_timestamp = item.get("date", 0) |
|
|
| if not after_status: |
| logging.warning(f"Task {task_id} update ignored: No status change detected.") |
| continue |
|
|
| action_date_human = datetime.utcfromtimestamp(int(action_timestamp) / 1000).strftime('%Y-%m-%d %H:%M:%S') if action_timestamp else "Unknown Date" |
|
|
| logging.info(f"Task: {task_name}, New Status: {after_status}, Action Date: {action_date_human}") |
|
|
| if after_status.lower() == "ready for review": |
| whatsapp_payload = { |
| "chatId": "201092003112@c.us", |
| "message": f"📝 *Task Submitted for Review!*\n\n📌 *Task:* {task_name}\n📅 *Submitted On:* {action_date_human}\n\n🔗 *View Task:* {task_link}\n\nPlease review the task and provide feedback." |
| } |
|
|
| try: |
| whatsapp_response = requests.post(WHATSAPP_URL, json=whatsapp_payload, headers=whatsapp_headers) |
| whatsapp_response.raise_for_status() |
| logging.info(f"WhatsApp API Response: {whatsapp_response.status_code} - {whatsapp_response.text}") |
| except requests.RequestException as e: |
| logging.error(f"Failed to send WhatsApp notification: {e}") |
|
|
| elif event_type == "taskTagUpdated": |
| history_items = data.get("history_items", []) |
| if history_items: |
| for history_item in history_items: |
| if "after" in history_item: |
| for tag in history_item["after"]: |
| tag_name = tag.get("name") |
| if tag_name and tag_name.lower() == "missed due date": |
| |
| task_details = get_task_details(task_id) |
| due_date_timestamp = task_details.get("due_date") |
| due_date = datetime.utcfromtimestamp(int(due_date_timestamp) / 1000).strftime('%Y-%m-%d') if due_date_timestamp else "Unknown Due Date" |
|
|
| logging.info(f"Missed Due Date Tag Added for Task: {task_name}, Due Date: {due_date}") |
|
|
| whatsapp_payload = { |
| "chatId": "201092003112@c.us", |
| "message": f"⚠️ *Task Missed Due Date!*\n\n📌 *Task:* {task_name}\n📅 *Due Date:* {due_date}\n\n🔗 *View Task:* {task_link}\n\nPlease take action immediately." |
| } |
|
|
| try: |
| whatsapp_response = requests.post(WHATSAPP_URL, json=whatsapp_payload, headers=whatsapp_headers) |
| whatsapp_response.raise_for_status() |
| logging.info(f"WhatsApp API Response: {whatsapp_response.status_code} - {whatsapp_response.text}") |
| except requests.RequestException as e: |
| logging.error(f"Failed to send WhatsApp notification: {e}") |
|
|
| return {"status": "Update received"} |