From cf94b7eb9b57d45d165408e11c7934b581fe6c52 Mon Sep 17 00:00:00 2001 From: tenzi Date: Tue, 7 Apr 2026 11:38:35 +0200 Subject: [PATCH] ts is done --- bot/__pycache__/task.cpython-313.pyc | Bin 2948 -> 2976 bytes bot/task.py | 1 - main.py | 61 +++++++++++++++++++++++---- requirements.txt | 42 ++++++++++++++++++ 4 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 requirements.txt diff --git a/bot/__pycache__/task.cpython-313.pyc b/bot/__pycache__/task.cpython-313.pyc index 7bd93ad600b92420b6f8428d84a387e84e3f040f..51046a5e2680aa27b6f377b3b594d7fbd496597a 100644 GIT binary patch delta 825 zcmb7COK%cU6h3$Eya#HdSWq-jh!q0F7NHWOeGI8hYtuv~(+vqo3ly}_W~ij@T=)Y_ zZo1Q?3s>%piA$5h(uHwjBB?*18(p|`<2_TF;L?-KcfNDacOH{_U;2;y-rruY4%{BU z{nBi`_ihX3PXbUOYV3t=dVs75QuXMPkTU_(J=?}W)bwW&oV zo@^PMi7wM^QgEk@*6>c=e`Aa+$&%R^oe0=M1hT_?ODm3@OW7;xYw&rRt=mS1TFO;; zqGtK-Xe(erg93EPAzha|&=zemc9w!_6oBt>aTt!c!sU@*NG+9bqOngjXcbjhpW&ZA z3B{>%r2>^{fVT1<9d%n7gWH1JHz@{l%A&H(_ib}uCv~__Lr^DoXr083bw}WX;$(1X z^I3DJTHdd8o_5Nen$vA=)mTIPDqrDwC&1>V*B;+MY*m_V$Ip-0iFA_%d!gMqem zuvOdJZ|=6^9%mdY@K0UgK-sH2-`TBHo$Kt49P~|M;;boW9S?^v`z&X?zc~AI3NPS? znml2evPQnM4dtjgp3jow31X(jW50;}+LW1to6^=Qe5E)!JwT^8 z^V~TL2#W|N!UcpSga-)A96Iye5T1Seep70-R(i0Mwi1Cx5h*d%AO)E0 zHa%#J>Azr1Jb5Xcy?7)Zd$5T&V>I#N4)79^CT_Cdd^7XS&Sc&@aJ_Ole>$Bei1TLs zOEvz%S&`h|2|!NE={X~3E`SI2A&Y|kNlW~_Ibb3@i)t0P0Qt!KyVSbBWGrtJXQd9ZZLu*@Zz zQTZmFX;X{(hJxY(fEa6HR6pS9$&;~+CI-`&rIUkIpaMFia^i->HRm9E!LHY!a0Q^I z+I`w~;y;ZHOC5)>G}2DC_n-rAVpi;?rpDFE(3VLVqI4F@^yq3R)5~po;8YvR;kz{rJlS|FYYl9$_LL2*2M3{kJKgehai8C;Uye# zuXc}o<4ilKn#rr=aDpU)^5JP2`8j_g0*5h@2+1Ar3EuIML|E?lW#pHr&~!osdAN@e zGa00vm?s&a-C2^HSGyhsxmOX&Za@*)ZctS57y3hT~5#XNp;yo*L- zH-%v_gcXE1!YPDX2&)LU1vH6(6?O*wJ2rSR;S})aHT;$&W$_mXU}x>T-(Ugc_(!nI Y2nn&1fMZ7OKN02k9n)l;mmSyt0n;~?Gynhq diff --git a/bot/task.py b/bot/task.py index e63ce8d..3a58d0f 100644 --- a/bot/task.py +++ b/bot/task.py @@ -7,7 +7,6 @@ class TaskSelect(Select): 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"] diff --git a/main.py b/main.py index 53a4ebb..2ac6672 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,6 @@ from bot.database import UserLocation from asyncio import to_thread from discord import app_commands from discord.ui import View, Select -from bot.task import TaskSelect, TasksView load_dotenv() DISCORD_TOKEN = os.getenv("DISCORD_TOKEN") @@ -63,6 +62,49 @@ async def authenticate(): f.write(credentials.to_json()) print(f"Saved credentials to {TOKEN_FILE} for instant access") +#Marl task as completed +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 + + if task.get("status") == "completed": + await interaction.followup.send("Task already completed.", 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(f"User: {interaction.user.display_name} marked task: '{updated.get('title')}' as completed.", ephemeral=True) + print(f"User {interaction.user.display_name} just completed task {updated.get('title')}") + + 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)) + @bot.tree.command(name="daily_tasks", description="Check today's saved tasks and complete them") async def today(interaction: discord.Interaction): @@ -83,7 +125,7 @@ async def today(interaction: discord.Interaction): ) options = [] - added = 0 + total = 0 for tl in lists: tl_id = tl.get("id") @@ -103,20 +145,21 @@ async def today(interaction: discord.Interaction): if due_date != today and completed_date != today: continue - + total += 1 status = "✅" if t.get("status") == "completed" else "🔲" t_id = t.get("id") title = t.get("title") or "(no title)" - embed.add_field(name=f"{tl_title} - {status} {title}", value=f"ID: {t.get('id')}", inline=False) + embed.add_field(name=f"{tl_title} - {status} {title}", value=f"ID: {t_id}", inline=False) - value = json.dumps({"tasklist_id": tl_id, "task_id": t.get("id")}) - options.append(discord.SelectOption(label=(title[:90] or "(no title)"), description=tl_title[:50], value=value)) - added += 1 + value = json.dumps({"tasklist_id": tl_id, "task_id": t_id}) + options.append(discord.SelectOption(label=(title[:90] or "(no title)"), description=tl_title[:50], value=value)) + - if added == 0: - embed.description = "No tasks due today." + if total == 0: + await interaction.followup.send("No tasks due today.") return + options = options[:25] view = TasksView(options, interaction.user.id) await interaction.followup.send(embed=embed, view=view) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8e8c4f6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,42 @@ +aiohappyeyeballs==2.6.1 +aiohttp==3.13.3 +aiosignal==1.4.0 +attrs==25.4.0 +audioop-lts==0.2.2 +certifi==2026.2.25 +cffi==2.0.0 +charset-normalizer==3.4.5 +cryptography==46.0.5 +davey==0.1.0 +discord==2.3.2 +discord.py==2.7.1 +frozenlist==1.8.0 +geographiclib==2.1 +geopy==2.4.1 +google-api-core==2.30.0 +google-api-python-client==2.192.0 +google-auth==2.49.1 +google-auth-httplib2==0.3.0 +google-auth-oauthlib==1.3.0 +googleapis-common-protos==1.73.0 +httplib2==0.31.2 +idna==3.11 +multidict==6.7.1 +oauthlib==3.3.1 +propcache==0.4.1 +proto-plus==1.27.1 +protobuf==6.33.5 +pyasn1==0.6.3 +pyasn1_modules==0.4.2 +pycparser==3.0 +PyNaCl==1.5.0 +pyparsing==3.3.2 +python-dateutil==2.9.0.post0 +python-dotenv==1.2.2 +pytz==2026.1.post1 +requests==2.32.5 +requests-oauthlib==2.0.0 +six==1.17.0 +uritemplate==4.2.0 +urllib3==2.6.3 +yarl==1.22.0