Skip to content

Commit 4e38eaa

Browse files
committed
fix: typeerror / refactor
1 parent e620a03 commit 4e38eaa

File tree

2 files changed

+104
-108
lines changed

2 files changed

+104
-108
lines changed

bot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,6 +1913,7 @@ async def on_message_delete(self, message):
19131913
"DM message not found.",
19141914
"Malformed thread message.",
19151915
"Thread message not found.",
1916+
"Linked DM message not found.",
19161917
}:
19171918
logger.debug("Failed to find linked message to delete: %s", e)
19181919
embed = discord.Embed(description="Failed to delete message.", color=self.error_color)

core/thread.py

Lines changed: 103 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -224,16 +224,12 @@ async def snooze(self, moderator=None, command_used=None, snooze_for=None):
224224
"author_name": (
225225
getattr(m.embeds[0].author, "name", "").split(" (")[0]
226226
if m.embeds and m.embeds[0].author and m.author == self.bot.user
227-
else getattr(m.author, "name", None)
228-
if m.author != self.bot.user
229-
else None
227+
else getattr(m.author, "name", None) if m.author != self.bot.user else None
230228
),
231229
"author_avatar": (
232230
getattr(m.embeds[0].author, "icon_url", None)
233231
if m.embeds and m.embeds[0].author and m.author == self.bot.user
234-
else m.author.display_avatar.url
235-
if m.author != self.bot.user
236-
else None
232+
else m.author.display_avatar.url if m.author != self.bot.user else None
237233
),
238234
}
239235
async for m in channel.history(limit=None, oldest_first=True)
@@ -1331,131 +1327,122 @@ async def find_linked_messages(
13311327
message1: discord.Message = None,
13321328
note: bool = True,
13331329
) -> typing.Tuple[discord.Message, typing.List[typing.Optional[discord.Message]]]:
1334-
if message1 is not None:
1335-
if note:
1336-
# For notes, don't require author.url; rely on footer/author.name markers
1337-
if not message1.embeds or message1.author != self.bot.user:
1338-
logger.warning(
1339-
f"Malformed note for deletion: embeds={bool(message1.embeds)}, author={message1.author}"
1340-
)
1341-
raise ValueError("Malformed note message.")
1330+
if message1 is None:
1331+
if message_id is not None:
1332+
try:
1333+
message1 = await self.channel.fetch_message(message_id)
1334+
except discord.NotFound:
1335+
logger.warning(f"Message ID {message_id} not found in channel history.")
1336+
raise ValueError("Thread message not found.")
13421337
else:
1343-
if (
1344-
not message1.embeds
1345-
or not message1.embeds[0].author.url
1346-
or message1.author != self.bot.user
1347-
):
1348-
is_plain = False
1349-
if message1.embeds and message1.embeds[0].footer and message1.embeds[0].footer.text:
1350-
if message1.embeds[0].footer.text.startswith("[PLAIN]"):
1351-
is_plain = True
1338+
# No ID provided - find last message sent by bot
1339+
async for msg in self.channel.history():
1340+
if msg.author != self.bot.user:
1341+
continue
1342+
if not msg.embeds:
1343+
continue
13521344

1353-
if not is_plain:
1354-
logger.debug(
1355-
f"Malformed thread message for deletion: embeds={bool(message1.embeds)}, author_url={getattr(message1.embeds[0], 'author', None) and message1.embeds[0].author.url}, author={message1.author}"
1356-
)
1357-
# Keep original error string to avoid extra failure embeds in on_message_delete
1358-
raise ValueError("Malformed thread message.")
1345+
is_valid_candidate = False
1346+
if (
1347+
msg.embeds[0].footer
1348+
and msg.embeds[0].footer.text
1349+
and msg.embeds[0].footer.text.startswith("[PLAIN]")
1350+
):
1351+
is_valid_candidate = True
1352+
elif msg.embeds[0].author.url and msg.embeds[0].author.url.split("#")[-1].isdigit():
1353+
is_valid_candidate = True
1354+
1355+
if is_valid_candidate:
1356+
message1 = msg
1357+
break
13591358

1360-
elif message_id is not None:
1361-
try:
1362-
message1 = await self.channel.fetch_message(message_id)
1363-
except discord.NotFound:
1364-
logger.warning(f"Message ID {message_id} not found in channel history.")
1365-
raise ValueError("Thread message not found.")
1359+
if message1 is None:
1360+
raise ValueError("No editable thread message found.")
1361+
1362+
is_note = False
1363+
if message1.embeds and message1.author == self.bot.user:
1364+
footer_text = (message1.embeds[0].footer and message1.embeds[0].footer.text) or ""
1365+
author_name = getattr(message1.embeds[0].author, "name", "") or ""
1366+
is_note = (
1367+
"internal note" in footer_text.lower()
1368+
or "persistent internal note" in footer_text.lower()
1369+
or author_name.startswith("📝 Note")
1370+
or author_name.startswith("📝 Persistent Note")
1371+
)
13661372

1367-
if note:
1368-
# Try to treat as note/persistent note first
1369-
if message1.embeds and message1.author == self.bot.user:
1370-
footer_text = (message1.embeds[0].footer and message1.embeds[0].footer.text) or ""
1371-
author_name = getattr(message1.embeds[0].author, "name", "") or ""
1372-
is_note = (
1373-
"internal note" in footer_text.lower()
1374-
or "persistent internal note" in footer_text.lower()
1375-
or author_name.startswith("📝 Note")
1376-
or author_name.startswith("📝 Persistent Note")
1377-
)
1378-
if is_note:
1379-
# Notes have no linked DM counterpart; keep None sentinel
1380-
return message1, None
1381-
# else: fall through to relay checks below
1382-
1383-
is_plain = False
1384-
if message1.embeds and message1.embeds[0].footer and message1.embeds[0].footer.text:
1385-
if message1.embeds[0].footer.text.startswith("[PLAIN]"):
1386-
is_plain = True
1387-
1388-
if is_plain:
1389-
creation_time = message1.created_at
1390-
1391-
mod_tag = message1.embeds[0].footer.text.replace("[PLAIN]", "", 1).strip()
1392-
author_name = message1.embeds[0].author.name
1393-
desc = message1.embeds[0].description or ""
1394-
prefix = f"**{mod_tag} " if mod_tag else "**"
1395-
plain_content_expected = f"{prefix}{author_name}:** {desc}"
1396-
1397-
messages = [message1]
1398-
for user in self.recipients:
1399-
async for msg in user.history(limit=50, around=creation_time):
1400-
if abs((msg.created_at - creation_time).total_seconds()) > 15:
1401-
continue
1402-
if msg.author != self.bot.user:
1403-
continue
1404-
if msg.embeds:
1405-
continue
1373+
if note and is_note:
1374+
return message1, None
14061375

1407-
if msg.content == plain_content_expected:
1408-
messages.append(msg)
1409-
break
1410-
1411-
if len(messages) > 1:
1412-
return messages
1413-
raise ValueError("Linked Plain DM message not found.")
1414-
1415-
if not is_plain and not (
1416-
message1.embeds
1417-
and message1.embeds[0].author.url
1418-
and message1.embeds[0].color
1419-
and message1.author == self.bot.user
1420-
):
1421-
logger.warning(
1422-
f"Message {message_id} is not a valid modmail relay message. embeds={bool(message1.embeds)}, author_url={getattr(message1.embeds[0], 'author', None) and message1.embeds[0].author.url}, color={getattr(message1.embeds[0], 'color', None)}, author={message1.author}"
1423-
)
1424-
raise ValueError("Thread message not found.")
1376+
if not note and is_note:
1377+
logger.warning("Message is an internal message, but note deletion/edit not requested.")
1378+
raise ValueError("Thread message is an internal message, not a note.")
14251379

1426-
if message1.embeds[0].footer and "Internal Message" in message1.embeds[0].footer.text:
1380+
if is_note:
1381+
return message1, None
1382+
1383+
is_plain = False
1384+
if message1.embeds and message1.embeds[0].footer and message1.embeds[0].footer.text:
1385+
if message1.embeds[0].footer.text.startswith("[PLAIN]"):
1386+
is_plain = True
1387+
1388+
if not is_plain:
1389+
# Relaxed mod_color check: only ensure author is bot and has url (which implies it's a relay)
1390+
# We rely on author.url existing for Joint ID
1391+
if not (message1.embeds and message1.embeds[0].author.url and message1.author == self.bot.user):
14271392
logger.warning(
1428-
f"Message {message_id} is an internal message, but note deletion not requested."
1393+
f"Message {message1.id} is not a valid modmail relay message. embeds={bool(message1.embeds)}, author={message1.author}"
14291394
)
1430-
raise ValueError("Thread message is an internal message, not a note.")
1431-
# Internal bot-only message treated similarly; keep None sentinel
1432-
return message1, None
1395+
raise ValueError("Thread message not found.")
14331396

14341397
try:
14351398
joint_id = int(message1.embeds[0].author.url.split("#")[-1])
1436-
except ValueError:
1399+
except (ValueError, AttributeError, IndexError):
14371400
raise ValueError("Malformed thread message.")
1438-
1439-
messages = [message1]
1401+
else:
1402+
joint_id = None
1403+
mod_tag = message1.embeds[0].footer.text.replace("[PLAIN]", "", 1).strip()
1404+
author_name = message1.embeds[0].author.name
1405+
desc = message1.embeds[0].description or ""
1406+
prefix = f"**{mod_tag} " if mod_tag else "**"
1407+
plain_content_expected = f"{prefix}{author_name}:** {desc}"
1408+
creation_time = message1.created_at
1409+
1410+
messages = [message1]
1411+
1412+
if is_plain:
1413+
for user in self.recipients:
1414+
async for msg in user.history(limit=50, around=creation_time):
1415+
if abs((msg.created_at - creation_time).total_seconds()) > 15:
1416+
continue
1417+
if msg.author != self.bot.user:
1418+
continue
1419+
if msg.embeds:
1420+
continue
1421+
1422+
if msg.content == plain_content_expected:
1423+
messages.append(msg)
1424+
break
1425+
else:
14401426
for user in self.recipients:
14411427
async for msg in user.history():
14421428
if either_direction:
14431429
if msg.id == joint_id:
1444-
return message1, msg
1430+
messages.append(msg)
1431+
break
14451432

14461433
if not (msg.embeds and msg.embeds[0].author.url):
14471434
continue
14481435
try:
14491436
if int(msg.embeds[0].author.url.split("#")[-1]) == joint_id:
14501437
messages.append(msg)
14511438
break
1452-
except ValueError:
1439+
except (ValueError, IndexError, AttributeError):
14531440
continue
14541441

1455-
if len(messages) > 1:
1456-
return messages
1442+
if len(messages) > 1:
1443+
return messages
14571444

1458-
raise ValueError("DM message not found.")
1445+
raise ValueError("Linked DM message not found.")
14591446

14601447
async def edit_message(self, message_id: typing.Optional[int], message: str) -> None:
14611448
try:
@@ -1480,9 +1467,17 @@ async def edit_message(self, message_id: typing.Optional[int], message: str) ->
14801467
else:
14811468
for m2 in message2:
14821469
if m2 is not None:
1483-
embed2 = m2.embeds[0]
1484-
embed2.description = message
1485-
tasks += [m2.edit(embed=embed2)]
1470+
if is_plain:
1471+
# Reconstruct the plain message format to preserve matching capability
1472+
mod_tag = embed1.footer.text.replace("[PLAIN]", "", 1).strip()
1473+
author_name = embed1.author.name
1474+
prefix = f"**{mod_tag} " if mod_tag else "**"
1475+
new_content = f"{prefix}{author_name}:** {message}"
1476+
tasks += [m2.edit(content=new_content)]
1477+
else:
1478+
embed2 = m2.embeds[0]
1479+
embed2.description = message
1480+
tasks += [m2.edit(embed=embed2)]
14861481

14871482
await asyncio.gather(*tasks)
14881483

0 commit comments

Comments
 (0)