mark task as complete unfinsihed

This commit is contained in:
Tenzing Kandang 2026-04-01 19:13:42 +02:00
parent cffb440809
commit 5e2ff7a859
8 changed files with 75 additions and 31 deletions

2
.gitignore vendored
View File

@ -4,4 +4,4 @@
/dvenv /dvenv
copy.txt copy.txt
user_location.db user_location.db
/utils/.env /bot/.env

Binary file not shown.

40
bot/task.py Normal file
View File

@ -0,0 +1,40 @@
import asyncio, json, datetime, discord
from discord.ui import View, Select
class TaskSelect(Select):
def __init__(self, options):
super().__init__(placeholder="Choose a task to complete...",
min_values=1, max_values=1, options=options)
async def callback(self, interaction: discord.Interaction):
payload = json.loads(self.values[0])
tasklist_id = payload["tasklist_id"]
task_id = payload["task_id"]
await interaction.response.defer(thinking=True)
try:
service = build_tasks_service()
task = await asyncio.to_thread(lambda:
service.tasks().get(tasklist=tasklist_id, task=task_id).execute())
if not task:
await interaction.followup.send("Task not found.", ephemeral=True)
return
now = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()
body = dict(task)
body["status"] = "completed"
body["completed"] = now
updated = await asyncio.to_thread(lambda: service.tasks().update(tasklist=tasklist_id, task=task_id, body=body).execute())
if updated.get("status") == "completed":
await interaction.followup.send("Failed to mark completed.", ephemeral=True)
except Exception as e:
await interaction.followup.send(f"Error: {e}", ephemeral=True)
class TasksView(View):
def __init__(self, options, timeout=120):
super().__init__(timeout=timeout)
self.add_item(TaskSelect(options))

64
main.py
View File

@ -1,14 +1,15 @@
import os import discord, asyncio, json, datetime, os
import discord
import datetime
from google_auth_oauthlib.flow import InstalledAppFlow from google_auth_oauthlib.flow import InstalledAppFlow
from utils.weather import OpenWeatherMapAPIClient from bot.weather import OpenWeatherMapAPIClient
from googleapiclient.discovery import build from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials from google.oauth2.credentials import Credentials
from discord.ext import commands from discord.ext import commands
from dotenv import load_dotenv from dotenv import load_dotenv
from utils.database import UserLocation from bot.database import UserLocation
from asyncio import to_thread from asyncio import to_thread
from discord import app_commands
from discord.ui import View, Select
from bot.task import TaskSelect, TasksView
load_dotenv() load_dotenv()
DISCORD_TOKEN = os.getenv("DISCORD_TOKEN") DISCORD_TOKEN = os.getenv("DISCORD_TOKEN")
@ -61,14 +62,16 @@ async def authenticate():
with open(TOKEN_FILE, 'w') as f: with open(TOKEN_FILE, 'w') as f:
f.write(credentials.to_json()) f.write(credentials.to_json())
print(f"Saved credentials to {TOKEN_FILE} for instant access") print(f"Saved credentials to {TOKEN_FILE} for instant access")
@bot.tree.command(name="daily_tasks", description="Check today's saved tasks") @bot.tree.command(name="daily_tasks", description="Check today's saved tasks and complete them")
async def today(interaction: discord.Interaction): async def today(interaction: discord.Interaction):
await interaction.response.defer(thinking=True) await interaction.response.defer(thinking=True)
print(f'Recieved daily_tasks command by {interaction.user.display_name}')
try: try:
service = build_tasks_service() service = build_tasks_service()
tl_res = service.tasklists().list(maxResults=100).execute() tl_res = await asyncio.to_thread(lambda: service.tasklists().list(maxResults=100).execute())
lists = tl_res.get("items", []) or [] lists = tl_res.get("items", []) or []
today = datetime.datetime.now(tz=TZ).date() today = datetime.datetime.now(tz=TZ).date()
@ -79,15 +82,16 @@ async def today(interaction: discord.Interaction):
timestamp=datetime.datetime.now(tz=TZ) timestamp=datetime.datetime.now(tz=TZ)
) )
options = []
added = 0 added = 0
for tl in lists: for tl in lists:
tl_id = tl.get("id") tl_id = tl.get("id")
tl_title = tl.get("title") or "<untitled>" tl_title = tl.get("title") or "<untitled>"
tasks_res = service.tasks().list( tasks_res = await asyncio.to_thread(lambda: service.tasks().list(
tasklist=tl_id, showCompleted=True, showHidden=True, maxResults=250).execute() or {} tasklist=tl_id, showCompleted=True, showHidden=True, maxResults=250).execute() or {})
items = tasks_res.get("items", []) or [] items = tasks_res.get("items", []) or []
lines = []
for t in items: for t in items:
if not isinstance(t, dict): if not isinstance(t, dict):
@ -96,35 +100,26 @@ async def today(interaction: discord.Interaction):
due_date = parse_rfc3339_to_local_date(t.get("due")) due_date = parse_rfc3339_to_local_date(t.get("due"))
completed_date = parse_rfc3339_to_local_date(t.get("completed")) completed_date = parse_rfc3339_to_local_date(t.get("completed"))
print("title:", t.get("title"), "due:", t.get("due"), "completed:", t.get("completed"), "status:", t.get("status"))
if due_date != today and completed_date != today: if due_date != today and completed_date != today:
continue continue
status = "" if t.get("status") == "completed" else "🔲" status = "" if t.get("status") == "completed" else "🔲"
t_id = t.get("id")
title = t.get("title") or "(no title)" title = t.get("title") or "(no title)"
if completed_date == today and t.get("completed"):
completed_short = t["completed"].replace("T", " ").split(".")[0]
lines.append(f"{status} {title} - completed {completed_short}")
else:
if due_date:
lines.append(f"{status} {title} (due {due_date.isoformat()})")
else:
lines.append(f"{status}{title}")
if not lines: embed.add_field(name=f"{tl_title} - {status} {title}", value=f"ID: {t.get('id')}", inline=False)
continue
value = "\n".join(lines)[:1024] value = json.dumps({"tasklist_id": tl_id, "task_id": t.get("id")})
embed.add_field(name=tl_title, value=value, inline=False) options.append(discord.SelectOption(label=(title[:90] or "(no title)"), description=tl_title[:50], value=value))
added += 1 added += 1
if added == 0: if added == 0:
embed.description = "No tasks due today." embed.description = "No tasks due today."
return
await interaction.followup.send(embed=embed) options = options[:25]
view = TasksView(options, interaction.user.id)
await interaction.followup.send(embed=embed, view=view)
except Exception as e: except Exception as e:
await interaction.followup.send(f"An error occured:{e}") await interaction.followup.send(f"An error occured:{e}")
@ -134,6 +129,7 @@ async def today(interaction: discord.Interaction):
async def events(interaction: discord.Interaction): async def events(interaction: discord.Interaction):
await interaction.response.defer(thinking=True) await interaction.response.defer(thinking=True)
print(f'Recieved weekly_events command by {interaction.user.display_name}')
try: try:
service = build_calendar_service() service = build_calendar_service()
except FileNotFoundError: except FileNotFoundError:
@ -246,13 +242,21 @@ async def on_ready():
print(f'Logged in as {bot.user}') print(f'Logged in as {bot.user}')
await authenticate() await authenticate()
await bot.tree.sync() await bot.tree.sync()
#Liste commandes enregistré #Liste commandes enregistré
commands = await bot.tree.fetch_commands() commands = await bot.tree.fetch_commands()
print("Registered Commands:") print("Registered Commands:")
for command in commands: for command in commands:
print(f"- {command.name}") print(f"- {command.name}")
print("- !set_location") print("- !set_location")
channel = bot.get_channel(1480922508566990879)
if channel:
embed = discord.Embed(
description="Bot is now online and ready to serve! Type / to check available commands"
)
await channel.send(embed=embed)
print("your bot is online and ready to serve !") print("your bot is online and ready to serve !")
bot.run(DISCORD_TOKEN) bot.run(DISCORD_TOKEN)