from fastapi import FastAPI, Request from pydantic import BaseModel import requests import logging from datetime import datetime # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') app = FastAPI() # ClickUp API URL for creating a task CLICKUP_URL_BASE = "https://api.clickup.com/api/v2" # WhatsApp API URL WHATSAPP_URL = "https://7105.api.greenapi.com/waInstance7105210836/sendMessage/805b69f6c85d4e6caea0edaba692b889abecc9e6bb8b457e8f" # Your access token ACCESS_TOKEN = "2144425825_36f2249dc27c5aca075ac5442b1bbcdf01c3a29b9e41b86bda46a6cf651acd0f" # Headers for ClickUp authorization headers = { "Authorization": ACCESS_TOKEN, "Content-Type": "application/json" } # Headers for WhatsApp API whatsapp_headers = { "Content-Type": "application/json" } class TaskData(BaseModel): task_name: str task_type: str # "Reel" or "Design" campaign_name: str platforms: list[str] assignees: list[int] # List of user IDs due_date: int # Unix timestamp in milliseconds @app.post("/singletask") async def create_task(request: Request): data = await request.json() logging.info(f"Received task data: {data}") # Extract and assign to variables 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 extracted values for debugging 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}") # Create ClickUp task according to task type 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}"} # Construct ClickUp task payload payload = { "name": task_title, "description": description_text, "assignees": [int(uid) for uid in assignee_ids], "status": status } # Handle due date 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.") # Send request to ClickUp 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}") # WhatsApp notification part is commented out for now # We'll handle WhatsApp notification later return {"status": "Task data received and parsed"} # Function to get task name by task ID 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 } # Make the API request to ClickUp response = requests.get(url, headers=headers) # Check if the request was successful (status code 200) if response.status_code == 200: # Parse and return the task details 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 def send_whatsapp_notification(chat_id: str, message: str): payload = { "chatId": chat_id, "message": message } try: response = requests.post(WHATSAPP_URL, json=payload, headers=whatsapp_headers) response.raise_for_status() logging.info(f"WhatsApp sent to {chat_id} - {response.status_code}: {response.text}") except requests.RequestException as e: logging.error(f"WhatsApp send failed for {chat_id}: {e}") @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") # Get task details 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": chat_id = "201092003112@c.us" message = ( f"📝 *Task Submitted for Review!*\n\n" f"📌 *Task:* {task_name}\n" f"📅 *Submitted On:* {action_date_human}\n\n" f"🔗 *View Task:* {task_link}\n\n" f"Please review the task and provide feedback." ) send_whatsapp_notification(chat_id, message) 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": # Get due date task_details = get_task_details(task_id) # Function to fetch task details print(f"Task details: {task_details}") # Extract assignee usernames assignee_usernames = [assignee['username'] for assignee in task_details.get('assignees', [])] print(assignee_usernames) 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}") chat_id = "201092003112@c.us" message = ( f"⚠️ *Task Missed Due Date!*\n\n" f"📌 *Task:* {task_name}\n" f"📅 *Due Date:* {due_date}\n\n" f"🔗 *View Task:* {task_link}\n\n" f"Please take action immediately." ) send_whatsapp_notification(chat_id, message) return {"status": "Update received"}