|
|
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/waInstance7105265861/sendMessage/f1e39ce29d1f4040a20f0718547a384ae2e0afb3d9884727ad" |
|
|
|
|
|
|
|
|
ACCESS_TOKEN = "2144425825_36f2249dc27c5aca075ac5442b1bbcdf01c3a29b9e41b86bda46a6cf651acd0f" |
|
|
|
|
|
|
|
|
web_app_url = "https://script.google.com/macros/s/AKfycbx9-oUXV896jM0HbQSz4h61Crf_UYHM8LJMbxXux4PHwf38zqjaJjIJe9O4UyT1u6s/exec" |
|
|
|
|
|
|
|
|
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}") |
|
|
|
|
|
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() |
|
|
|
|
|
|
|
|
template_ids = { |
|
|
"content": "t-8698wwx4z", |
|
|
"creative": "t-8698wwx4z", |
|
|
"ads": "t-8698wwx4z" |
|
|
} |
|
|
custom_field_id = "64b6898b-eaee-4dd1-b819-a5b142226f69" |
|
|
team_id = "9012303718" |
|
|
|
|
|
|
|
|
if task_type_lower == "content": |
|
|
status = "backlog" |
|
|
description_text = goal.strip() |
|
|
if platforms: |
|
|
description_text += "\n\nPlatforms: " + ", ".join(platforms) |
|
|
|
|
|
elif task_type_lower == "creative": |
|
|
status = "to do" |
|
|
description_text = creative_type.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) |
|
|
|
|
|
if task_type_lower in template_ids: |
|
|
|
|
|
template_id = template_ids[task_type_lower] |
|
|
template_url = f"{CLICKUP_URL_BASE}/list/{list_id}/taskTemplate/{template_id}" |
|
|
template_payload = { |
|
|
"name": task_title |
|
|
} |
|
|
|
|
|
response = requests.post(template_url, headers=headers, json=template_payload) |
|
|
print("Template Creation Status:", response.status_code) |
|
|
print(f"Template Creation response {response.json()}") |
|
|
|
|
|
if response.ok: |
|
|
new_task = response.json() |
|
|
new_task_id = new_task.get("id") |
|
|
space_id = new_task.get("task", {}).get("space", {}).get("id") |
|
|
|
|
|
print("✅ Task created from template:", new_task_id) |
|
|
print(f"Space id is {space_id}") |
|
|
|
|
|
|
|
|
update_payload = { |
|
|
"assignees": { |
|
|
"add": [int(uid) for uid in assignee_ids], |
|
|
"rem": [] |
|
|
}, |
|
|
"status": status |
|
|
} |
|
|
|
|
|
|
|
|
if deadline: |
|
|
try: |
|
|
due_timestamp = int(datetime.strptime(deadline, "%Y-%m-%d").timestamp() * 1000) |
|
|
update_payload["due_date"] = due_timestamp |
|
|
print(f"📅 Due Date (timestamp): {due_timestamp}") |
|
|
except ValueError: |
|
|
print("❌ Invalid deadline format. Skipping due_date.") |
|
|
|
|
|
print(f"Update payload is {update_payload}\n") |
|
|
|
|
|
update_url = f"{CLICKUP_URL_BASE}/task/{new_task_id}" |
|
|
update_response = requests.put(update_url, headers=headers, json=update_payload) |
|
|
print("🔧 Update Status:", update_response.status_code) |
|
|
print("🧾 Update Response:", update_response.text) |
|
|
|
|
|
|
|
|
update_field_url = f"{CLICKUP_URL_BASE}/task/{new_task_id}/field/{custom_field_id}?custom_task_ids=true&team_id={team_id}" |
|
|
field_payload = {"value": description_text} |
|
|
field_update = requests.post(update_field_url, headers=headers, json=field_payload) |
|
|
|
|
|
print("📥 Field Update Status:", field_update.status_code) |
|
|
print("📥 Field Update Response:", field_update.text) |
|
|
|
|
|
|
|
|
for assignee_id in assignee_ids: |
|
|
params = { |
|
|
"mode": "notify-assigned", |
|
|
"assigneeId": assignee_id, |
|
|
"spaceId": space_id |
|
|
} |
|
|
|
|
|
response = requests.get(web_app_url, params=params) |
|
|
print(f"Assignee to notify {response.json()}") |
|
|
if response.ok: |
|
|
phone = response.json().get("phone") |
|
|
if phone and phone != "not-found": |
|
|
chat_id = f"{phone}@c.us" |
|
|
task_url = f"https://app.clickup.com/t/{new_task_id}" |
|
|
task_name = task_title |
|
|
if deadline: |
|
|
due_str = datetime.utcfromtimestamp(due_timestamp / 1000).strftime('%Y-%m-%d') |
|
|
msg = ( |
|
|
f"📌 *تم تعيين مهمة جديدة لك!*\n\n" |
|
|
f"📝 *اسم المهمة:* {task_name}\n" |
|
|
f"📅 *تاريخ التسليم:* {due_str}\n" |
|
|
f"🔗 *رابط المهمة:* {task_url}" |
|
|
) |
|
|
else: |
|
|
msg = ( |
|
|
f"📌 *تم تعيين مهمة جديدة لك!*\n\n" |
|
|
f"📝 *اسم المهمة:* {task_name}\n" |
|
|
f"🔗 *رابط المهمة:* {task_url}" |
|
|
) |
|
|
send_whatsapp_notification(chat_id, msg) |
|
|
else: |
|
|
logging.warning(f"❌ Couldn't fetch phone number for assignee {assignee_id}") |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
"status": "Template-based task created", |
|
|
"task_id": new_task_id |
|
|
} |
|
|
else: |
|
|
print("❌ Failed to create task from template") |
|
|
return {"error": "Template task creation failed"} |
|
|
|
|
|
|
|
|
elif task_type_lower in ["strategy", "posting", "ads report"]: |
|
|
if task_type_lower == "strategy": |
|
|
status = "to do" |
|
|
description_text = description |
|
|
|
|
|
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}" |
|
|
|
|
|
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.") |
|
|
|
|
|
print(f"Task payload is {payload}\n") |
|
|
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}") |
|
|
|
|
|
|
|
|
|
|
|
new_task_id = clickup_data.get("id") |
|
|
space_id = clickup_data.get("space", {}).get("id") |
|
|
assignee_ids = [str(uid) for uid in assignee_ids] |
|
|
|
|
|
|
|
|
for assignee_id in assignee_ids: |
|
|
params = { |
|
|
"mode": "notify-assigned", |
|
|
"assigneeId": assignee_id, |
|
|
"spaceId": space_id |
|
|
} |
|
|
|
|
|
response = requests.get(web_app_url, params=params) |
|
|
print(f"Assingnee to notify {response.json()}") |
|
|
if response.ok: |
|
|
phone = response.json().get("phone") |
|
|
if phone and phone != "not-found": |
|
|
chat_id = f"{phone}@c.us" |
|
|
task_url = f"https://app.clickup.com/t/{new_task_id}" |
|
|
task_name = payload["name"] |
|
|
due_date = payload.get("due_date") |
|
|
if due_date: |
|
|
due_str = datetime.utcfromtimestamp(due_date / 1000).strftime('%Y-%m-%d') |
|
|
msg = ( |
|
|
f"📌 *تم تعيين مهمة جديدة لك!*\n\n" |
|
|
f"📝 *اسم المهمة:* {task_name}\n" |
|
|
f"📅 *تاريخ التسليم:* {due_str}\n" |
|
|
f"🔗 *رابط المهمة:* {task_url}" |
|
|
) |
|
|
else: |
|
|
msg = ( |
|
|
f"📌 *تم تعيين مهمة جديدة لك!*\n\n" |
|
|
f"📝 *اسم المهمة:* {task_name}\n" |
|
|
f"🔗 *رابط المهمة:* {task_url}" |
|
|
) |
|
|
send_whatsapp_notification(chat_id, msg) |
|
|
return {"status": "Standard task created", "clickup": clickup_data} |
|
|
|
|
|
else: |
|
|
logging.warning(f"❌ Couldn't fetch phone number for assignee {assignee_id}") |
|
|
|
|
|
else: |
|
|
return {"error": f"Unsupported task type: {task_type}"} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
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") |
|
|
|
|
|
|
|
|
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": |
|
|
|
|
|
task_details = get_task_details(task_id) |
|
|
print(f"Task details: {task_details}") |
|
|
|
|
|
task_name = task_details.get("name", "Unnamed Task") |
|
|
task_url = task_details.get("url", "") |
|
|
space_id = task_details.get("space", {}).get("id") |
|
|
assignees = task_details.get("assignees", []) |
|
|
assignee_ids = [str(assignee['id']) for assignee in assignees] |
|
|
assignee_id_to_name = {str(assignee['id']): assignee['username'] for assignee in assignees} |
|
|
assignee_names_str = "، ".join(assignee_id_to_name.values()) |
|
|
|
|
|
print(f"Assignees: {assignee_ids}") |
|
|
|
|
|
params = { |
|
|
"mode": "notify-roles", |
|
|
"assigneeId": assignee_ids[0], |
|
|
"spaceId": space_id |
|
|
} |
|
|
response = requests.get(web_app_url, params=params) |
|
|
|
|
|
if response.ok: |
|
|
notify_map = response.json() |
|
|
print("✅ Notify Map:", notify_map) |
|
|
|
|
|
|
|
|
user_dict = notify_map.get("users", {}) |
|
|
for user_id, number in user_dict.items(): |
|
|
chat_id = f"{number}@c.us" |
|
|
user_message = ( |
|
|
f"✅ *تم نقل المهمة للمراجعة بنجاح!*\n\n" |
|
|
f"📌 *المهمة:* {task_name}\n" |
|
|
f"📅 *التاريخ:* {action_date_human}\n" |
|
|
f"🔗 *رابط المهمة:* {task_url}\n\n" |
|
|
f"شكراً لك على استكمال المهمة." |
|
|
) |
|
|
send_whatsapp_notification(chat_id, user_message) |
|
|
|
|
|
|
|
|
notify_users = notify_map.get("notifyUsers", []) |
|
|
for user in notify_users: |
|
|
name = user.get("name", "عضو الفريق") |
|
|
number = user.get("phone") |
|
|
if number: |
|
|
chat_id = f"{number}@c.us" |
|
|
notify_message = ( |
|
|
f"📣 *تنبيه للفريق:*\n\n" |
|
|
f"📌 *{assignee_names_str}* قام بنقل المهمة التالية للمراجعة:\n" |
|
|
f"*{task_name}*\n" |
|
|
f"🔗 {task_url}\n\n" |
|
|
f"يرجى مراجعة المهمة وإضافة ملاحظاتك." |
|
|
) |
|
|
send_whatsapp_notification(chat_id, notify_message) |
|
|
|
|
|
|
|
|
managers = notify_map.get("managers", []) |
|
|
for manager in managers: |
|
|
manager_name = manager.get("name", "مدير") |
|
|
number = manager.get("phone") |
|
|
if number: |
|
|
chat_id = f"{number}@c.us" |
|
|
manager_message = ( |
|
|
f"👤 *إشعار للمدير:*\n\n" |
|
|
f"📌 *{assignee_names_str}* قام بنقل المهمة للمراجعة:\n" |
|
|
f"*{task_name}*\n" |
|
|
f"🔗 {task_url}\n\n" |
|
|
f"يمكنك إلقاء نظرة وإضافة ملاحظات إن وجدت." |
|
|
) |
|
|
send_whatsapp_notification(chat_id, manager_message) |
|
|
else: |
|
|
logging.error(f"❌ Failed to fetch notify-roles data: {response.status_code}") |
|
|
print("Raw response:", response.text) |
|
|
|
|
|
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) |
|
|
print(f"Task details: {task_details}") |
|
|
|
|
|
|
|
|
assignee_ids = [str(assignee['id']) for assignee in task_details.get('assignees', [])] |
|
|
print("Assignee IDs:", assignee_ids) |
|
|
|
|
|
|
|
|
space_id = task_details.get("space", {}).get("id") |
|
|
|
|
|
|
|
|
|
|
|
params = { |
|
|
"mode": "notify", |
|
|
"spaceId": space_id, |
|
|
} |
|
|
|
|
|
|
|
|
for assignee_id in assignee_ids: |
|
|
params.setdefault("assignees", []).append(assignee_id) |
|
|
|
|
|
|
|
|
task_name = task_details.get("name", "Unnamed Task") |
|
|
|
|
|
|
|
|
assignee_id_to_name = { |
|
|
str(assignee.get("id")): assignee.get("username") |
|
|
for assignee in task_details.get("assignees", []) |
|
|
} |
|
|
|
|
|
|
|
|
print("📝 Task Name:", task_name) |
|
|
|
|
|
task_url = task_details.get("url", "") |
|
|
print("🔗 Task URL:", task_url) |
|
|
|
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
response = requests.get(web_app_url, params=params) |
|
|
|
|
|
|
|
|
if response.ok: |
|
|
notify_map = response.json() |
|
|
print("✅ Notify Map:", notify_map) |
|
|
|
|
|
|
|
|
user_dict = notify_map.get("users", {}) |
|
|
manager_entries = notify_map.get("managers", []) |
|
|
|
|
|
|
|
|
user_numbers = list(user_dict.values()) |
|
|
|
|
|
|
|
|
user_names = [ |
|
|
assignee_id_to_name.get(user_id, f"User {user_id}") |
|
|
for user_id in user_dict.keys() |
|
|
] |
|
|
assignee_name_str = "، ".join(user_names) |
|
|
|
|
|
print("📞 User Numbers:", user_numbers) |
|
|
print("👥 Assignee Name(s) for Manager Message:", assignee_name_str) |
|
|
|
|
|
|
|
|
user_message = ( |
|
|
f"⚠️ *تنبيه بتأخر المهمة!*\n\n" |
|
|
f"📌 *المهمة:* {task_name}\n" |
|
|
f"📅 *تاريخ التسليم:* {due_date}\n" |
|
|
f"🔗 *رابط المهمة:* {task_url}\n\n" |
|
|
f"يرجى اتخاذ الإجراء اللازم فوراً." |
|
|
) |
|
|
|
|
|
for num in user_numbers: |
|
|
chat_id = f"{num}@c.us" |
|
|
send_whatsapp_notification(chat_id, user_message) |
|
|
|
|
|
for manager in manager_entries: |
|
|
manager_name = manager.get("name", "مدير غير معروف") |
|
|
manager_number = manager.get("number") |
|
|
if manager_number: |
|
|
chat_id = f"{manager_number}@c.us" |
|
|
personalized_message = ( |
|
|
f"📣 *تنبيه مهم:*\n\n" |
|
|
f"📌 مرحباً {manager_name}\n" |
|
|
f"📌 *الموظف:* {assignee_name_str}\n" |
|
|
f"❌ *تأخر في مهمة:* {task_name}\n" |
|
|
f"📅 *تاريخ التسليم:* {due_date}\n" |
|
|
f"🔗 *رابط المهمة:* {task_url}\n\n" |
|
|
f"يرجى المتابعة مع الفريق." |
|
|
) |
|
|
send_whatsapp_notification(chat_id, personalized_message) |
|
|
|
|
|
else: |
|
|
print("❌ Failed to fetch notify data:", response.status_code) |
|
|
print("Raw response:", response.text) |
|
|
|
|
|
logging.info(f"Missed Due Date Tag Added for Task: {task_name}, Due Date: {due_date}") |
|
|
|
|
|
return {"status": "Update received"} |