Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add persistent notes #2878

Merged
merged 9 commits into from
Nov 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
This project mostly adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html);
however, insignificant breaking changes do not guarantee a major version bump, see the reasoning [here](https://github.com/kyb3r/modmail/issues/319). If you're a plugin developer, note the "BREAKING" section.

# v3.7.0-dev12
# v3.7.0-dev13

### Added

Expand All @@ -27,6 +27,7 @@ however, insignificant breaking changes do not guarantee a major version bump, s
- Added support for thread titles, `?title`. ([GH #2838](https://github.com/kyb3r/modmail/issues/2838))
- Added `data_collection` to specify if bot metadata should be collected by Modmail developers.
- Added `?autotrigger`, `use_regex_autotrigger` config to specify keywords to trigger commands. ([GH #130](https://github.com/kyb3r/modmail/issues/130), [GH #649](https://github.com/kyb3r/modmail/issues/649))
- Added `?note persistent` that creates notes that are persistent for a user.

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion bot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "3.7.0-dev12"
__version__ = "3.7.0-dev13"


import asyncio
Expand Down
17 changes: 16 additions & 1 deletion cogs/modmail.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ async def pareply(self, ctx, *, msg: str = ""):
async with ctx.typing():
await ctx.thread.reply(ctx.message, anonymous=True, plain=True)

@commands.command()
@commands.group(invoke_without_command=True)
@checks.has_permissions(PermissionLevel.SUPPORTER)
@checks.thread_only()
async def note(self, ctx, *, msg: str = ""):
Expand All @@ -888,6 +888,21 @@ async def note(self, ctx, *, msg: str = ""):
msg = await ctx.thread.note(ctx.message)
await msg.pin()

@note.command(name="persistent", aliases=["persist"])
@checks.has_permissions(PermissionLevel.SUPPORTER)
@checks.thread_only()
async def note_persistent(self, ctx, *, msg: str = ""):
"""
Take a persistent note about the current user.
"""
ctx.message.content = msg
async with ctx.typing():
msg = await ctx.thread.note(ctx.message, persistent=True)
await msg.pin()
await self.bot.api.create_note(
recipient=ctx.thread.recipient, message=ctx.message, message_id=msg.id
)

@commands.command()
@checks.has_permissions(PermissionLevel.SUPPORTER)
@checks.thread_only()
Expand Down
47 changes: 47 additions & 0 deletions core/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@ async def search_closed_by(self, user_id: Union[int, str]):
async def search_by_text(self, text: str, limit: Optional[int]):
return NotImplemented

async def create_note(self, recipient: Member, message: Message, message_id: Union[int, str]):
return NotImplemented

async def find_notes(self, recipient: Member):
return NotImplemented

async def update_note_ids(self, ids: dict):
return NotImplemented

async def delete_note(self, message_id: Union[int, str]):
return NotImplemented

async def edit_note(self, message_id: Union[int, str], message: str):
return NotImplemented

def get_plugin_partition(self, cog):
return NotImplemented

Expand Down Expand Up @@ -401,6 +416,38 @@ async def search_by_text(self, text: str, limit: Optional[int]):
{"messages": {"$slice": 5}},
).to_list(limit)

async def create_note(self, recipient: Member, message: Message, message_id: Union[int, str]):
await self.db.notes.insert_one(
{
"recipient": str(recipient.id),
"author": {
"id": str(message.author.id),
"name": message.author.name,
"discriminator": message.author.discriminator,
"avatar_url": str(message.author.avatar_url),
},
"message": message.content,
"message_id": str(message_id),
}
)

async def find_notes(self, recipient: Member):
return await self.db.notes.find({"recipient": str(recipient.id)}).to_list(None)

async def update_note_ids(self, ids: dict):
for object_id, message_id in ids.items():
await self.db.notes.update_one(
{"_id": object_id}, {"$set": {"message_id": message_id}}
)

async def delete_note(self, message_id: Union[int, str]):
await self.db.notes.delete_one({"message_id": str(message_id)})

async def edit_note(self, message_id: Union[int, str], message: str):
await self.db.notes.update_one(
{"message_id": str(message_id)}, {"$set": {"message": message}}
)

def get_plugin_partition(self, cog):
cls_name = cog.__class__.__name__
return self.db.plugins[cls_name]
Expand Down
71 changes: 63 additions & 8 deletions core/thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
import typing
from datetime import datetime, timedelta
import time
from types import SimpleNamespace

import isodate
Expand Down Expand Up @@ -198,6 +199,42 @@ async def send_recipient_genesis_message():
close_emoji = await self.bot.convert_emoji(close_emoji)
await self.bot.add_reaction(msg, close_emoji)

async def send_persistent_notes():
notes = await self.bot.api.find_notes(self.recipient)
ids = {}

class State:
def store_user(self, user):
return user

for note in notes:
author = note["author"]

class Author:
name = author["name"]
id = author["id"]
discriminator = author["discriminator"]
avatar_url = author["avatar_url"]

data = {
"id": round(time.time() * 1000 - discord.utils.DISCORD_EPOCH) << 22,
"attachments": {},
"embeds": {},
"edited_timestamp": None,
"type": None,
"pinned": None,
"mention_everyone": None,
"tts": None,
"content": note["message"],
"author": Author(),
}
message = discord.Message(state=State(), channel=None, data=data)
ids[note["_id"]] = str(
(await self.note(message, persistent=True, thread_creation=True)).id
)

await self.bot.api.update_note_ids(ids)

async def activate_auto_triggers():
message = DummyMessage(copy.copy(initial_message))
if message:
Expand All @@ -207,7 +244,10 @@ async def activate_auto_triggers():
pass

await asyncio.gather(
send_genesis_message(), send_recipient_genesis_message(), activate_auto_triggers(),
send_genesis_message(),
send_recipient_genesis_message(),
activate_auto_triggers(),
send_persistent_notes(),
)
self.bot.dispatch("thread_ready", self)

Expand Down Expand Up @@ -528,9 +568,10 @@ async def find_linked_messages(
):
raise ValueError("Thread message not found.")

if message1.embeds[0].color.value == self.bot.main_color and message1.embeds[
0
].author.name.startswith("Note"):
if message1.embeds[0].color.value == self.bot.main_color and (
message1.embeds[0].author.name.startswith("Note")
or message1.embeds[0].author.name.startswith("Persistent Note")
):
if not note:
raise ValueError("Thread message not found.")
return message1, None
Expand Down Expand Up @@ -593,6 +634,8 @@ async def edit_message(self, message_id: typing.Optional[int], message: str) ->
embed2 = message2.embeds[0]
embed2.description = message
tasks += [message2.edit(embed=embed2)]
elif message1.embeds[0].author.name.startswith("Persistent Note"):
tasks += [self.bot.api.edit_note(message1.id, message)]

await asyncio.gather(*tasks)

Expand All @@ -608,6 +651,8 @@ async def delete_message(
tasks += [message1.delete()]
if message2 is not None:
tasks += [message2.delete()]
elif message1.embeds[0].author.name.startswith("Persistent Note"):
tasks += [self.bot.api.delete_note(message1.id)]
if tasks:
await asyncio.gather(*tasks)

Expand Down Expand Up @@ -647,11 +692,19 @@ async def edit_dm_message(self, message: discord.Message, content: str) -> None:
self.bot.api.edit_message(message.id, content), linked_message.edit(embed=embed)
)

async def note(self, message: discord.Message) -> None:
async def note(
self, message: discord.Message, persistent=False, thread_creation=False
) -> None:
if not message.content and not message.attachments:
raise MissingRequiredArgument(SimpleNamespace(name="msg"))

msg = await self.send(message, self.channel, note=True)
msg = await self.send(
message,
self.channel,
note=True,
persistent_note=persistent,
thread_creation=thread_creation,
)

self.bot.loop.create_task(
self.bot.api.append_log(
Expand Down Expand Up @@ -737,6 +790,8 @@ async def send(
note: bool = False,
anonymous: bool = False,
plain: bool = False,
persistent_note: bool = False,
thread_creation: bool = False,
) -> None:

self.bot.loop.create_task(
Expand Down Expand Up @@ -798,7 +853,7 @@ async def send(
else:
# Special note messages
embed.set_author(
name=f"Note ({author.name})",
name=f"{'Persistent' if persistent_note else ''} Note ({author.name})",
icon_url=system_avatar_url,
url=f"https://discordapp.com/users/{author.id}#{message.id}",
)
Expand Down Expand Up @@ -886,7 +941,7 @@ async def send(
embed.set_footer(text=f"Message ID: {message.id}")
embed.colour = self.bot.recipient_color

if from_mod or note:
if (from_mod or note) and not thread_creation:
delete_message = not bool(message.attachments)
if delete_message and destination == self.channel:
try:
Expand Down