Multiple changes
Started switching to generics Added tickets
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
"load_list": [
|
||||
"admin",
|
||||
"exec",
|
||||
"message_events"
|
||||
"message_events",
|
||||
"tickets"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,218 @@
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from geeksbot.imports.utils import Paginator, Book
|
||||
|
||||
|
||||
class Tickets(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command()
|
||||
async def request(self, ctx, *, message=None):
|
||||
if not ctx.guild:
|
||||
await ctx.send('This command must be run from inside a guild.')
|
||||
return
|
||||
|
||||
if not message:
|
||||
await ctx.send('Please include a message containing your request')
|
||||
return
|
||||
|
||||
if len(message) > 1000:
|
||||
await ctx.send('Request is too long, please keep your request to less than 1000 characters.')
|
||||
return
|
||||
|
||||
data = {
|
||||
'author': ctx.author.id,
|
||||
'message': ctx.message.id,
|
||||
'channel': ctx.channel.id,
|
||||
'content': message
|
||||
}
|
||||
msg_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/messages/{ctx.message.id}/wait/', headers=self.bot.auth_header)
|
||||
if msg_resp.status == 404:
|
||||
error = await msg_resp.json()
|
||||
await ctx.send(error['details'])
|
||||
return
|
||||
|
||||
resp = await self.bot.aio_session.post(f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/', headers=self.bot.auth_header, json=data)
|
||||
|
||||
if resp.status == 201:
|
||||
admin_channel_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/channels/{ctx.guild.id}/admin/', headers=self.bot.auth_header)
|
||||
request = await resp.json()
|
||||
|
||||
if admin_channel_resp.status == 200:
|
||||
admin_chan_data = await admin_channel_resp.json()
|
||||
msg = f''
|
||||
admin_roles_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/guilds/{ctx.guild.id}/roles/admin/', headers=self.bot.auth_header)
|
||||
if admin_roles_resp.status == 200:
|
||||
admin_roles_data = await admin_roles_resp.json()
|
||||
for role in admin_roles_data:
|
||||
msg += f'{ctx.guild.get_role(int(role["id"])).mention} '
|
||||
msg += f"New Request ID: {request['id']} " \
|
||||
f"{ctx.author.mention} has requested assistance: \n" \
|
||||
f"```{request['content']}``` \n" \
|
||||
f"Requested at: {request['requested_at'].split('.')[0].replace('T', ' ')} GMT\n" \
|
||||
f"In {ctx.guild.get_channel(int(request['channel'])).name}"
|
||||
admin_chan = ctx.guild.get_channel(int(admin_chan_data['id']))
|
||||
await admin_chan.send(msg)
|
||||
await ctx.send(f'{ctx.author.mention} The admin have received your request.\n'
|
||||
f'If you would like to update or close your request please reference Request ID `{request["id"]}`')
|
||||
|
||||
@commands.command(aliases=['comment'])
|
||||
async def update(self, ctx, request_id=None, *, comment: str = None):
|
||||
try:
|
||||
request_id = int(request_id)
|
||||
except ValueError:
|
||||
await ctx.send("Please include the ID of the request you would like to update as the first thing after the command.")
|
||||
return
|
||||
|
||||
if not comment:
|
||||
await ctx.send("There is nothing to update since you didn't include a message.")
|
||||
return
|
||||
|
||||
data = {
|
||||
'author': ctx.author.id,
|
||||
'content': comment
|
||||
}
|
||||
|
||||
comment_resp = await self.bot.aio_session.post(f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/{request_id}/comments/', headers=self.bot.auth_header, json=data)
|
||||
|
||||
if comment_resp.status == 201:
|
||||
comment = await comment_resp.json()
|
||||
admin_channel_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/channels/{ctx.guild.id}/admin/',
|
||||
headers=self.bot.auth_header)
|
||||
|
||||
if admin_channel_resp.status == 200:
|
||||
admin_channel_data = await admin_channel_resp.json()
|
||||
admin_channel = ctx.guild.get_channel(int(admin_channel_data['id']))
|
||||
if admin_channel:
|
||||
request_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/{request_id}/', headers=self.bot.auth_header)
|
||||
pag = Paginator(self.bot, prefix='```md', suffix='```')
|
||||
header = f'{ctx.author.mention} has commented on request {request_id}\n'
|
||||
if request_resp.status == 200:
|
||||
request = await request_resp.json()
|
||||
requestor = ctx.guild.get_member(int(request["author"]))
|
||||
header += (f'Original Request by {requestor.mention if requestor else "`User cannot be found`"}:\n'
|
||||
f'```{request["content"]}```')
|
||||
pag.set_header(header)
|
||||
|
||||
if request.get('comments'):
|
||||
comments = request['comments']
|
||||
for comment in comments:
|
||||
author = ctx.guild.get_member(int(comment['author']))
|
||||
pag.add(f'{author.display_name}: {comment["content"]}', keep_intact=True)
|
||||
if ctx.author != requestor and requestor:
|
||||
for page in pag.pages(page_headers=False):
|
||||
await requestor.send(page)
|
||||
book = Book(pag, (None, admin_channel, self.bot, ctx.message))
|
||||
await book.create_book()
|
||||
await ctx.send(f'{ctx.author.mention} Your comment has been added to the request.')
|
||||
|
||||
@commands.command(name='requests_list', aliases=['rl'])
|
||||
async def _requests_list(self, ctx, closed: str = ''):
|
||||
pag = Paginator(self.bot)
|
||||
admin_roles_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/guilds/{ctx.guild.id}/roles/admin/', headers=self.bot.auth_header)
|
||||
if admin_roles_resp.status == 200:
|
||||
admin_roles_data = await admin_roles_resp.json()
|
||||
admin_roles = [ctx.guild.get_role(int(role['id'])) for role in admin_roles_data]
|
||||
if any([role in ctx.author.roles for role in admin_roles]):
|
||||
requests_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/', headers=self.bot.auth_header)
|
||||
if requests_resp.status == 200:
|
||||
requests_data = await requests_resp.json()
|
||||
requests_list = requests_data['requests'] if isinstance(requests_data, dict) else requests_data
|
||||
while isinstance(requests_data, dict) and requests_data.get('next'):
|
||||
requests_resp = await self.bot.aio_session.get(
|
||||
requests_data['next'], headers=self.bot.auth_header)
|
||||
if requests_resp.status == 200:
|
||||
requests_data = await requests_resp.json()
|
||||
requests_list.extend(requests_data['requests'] if isinstance(requests_data, dict) else requests_data)
|
||||
for request in requests_list:
|
||||
member = discord.utils.get(ctx.guild.members, id=int(request['author']))
|
||||
title = (f"<{'Request ID':^20} {'Requested By':^20}>\n"
|
||||
f"<{request['id']:^20} {member.display_name if member else 'None':^20}>")
|
||||
orig_channel = ctx.guild.get_channel(int(request.get('channel')))
|
||||
comments_count_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/{request["id"]}/comments/count/', headers=self.bot.auth_header)
|
||||
pag.add(f"\n\n{title}\n"
|
||||
f"{request['content']}\n\n"
|
||||
f"Comments: {await comments_count_resp.text() if comments_count_resp.status == 200 else 0}\n"
|
||||
f"Requested at: "
|
||||
f"{request['requested_at'].split('.')[0].replace('T', ' ')} GMT\n"
|
||||
f"In {orig_channel.name if orig_channel else 'N/A'}", keep_intact=True)
|
||||
pag.add(f'\n\uFFF8\nThere are currently {len(requests_list)} requests open.')
|
||||
else:
|
||||
pag.add('There are no open requests for this guild.', keep_intact=True)
|
||||
else:
|
||||
requests_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/user/{ctx.author.id}/',
|
||||
headers=self.bot.auth_header)
|
||||
if requests_resp.status == 200:
|
||||
requests_data = await requests_resp.json()
|
||||
requests_list = requests_data['requests'] if isinstance(requests_data, dict) else requests_data
|
||||
while isinstance(requests_data, dict) and requests_data.get('next'):
|
||||
requests_resp = await self.bot.aio_session.get(
|
||||
requests_data['next'], headers=self.bot.auth_header)
|
||||
if requests_resp.status == 200:
|
||||
requests_data = await requests_resp.json()
|
||||
requests_list.extend(
|
||||
requests_data['requests'] if isinstance(requests_data, dict) else requests_data)
|
||||
for request in requests_list:
|
||||
title = (f"<{'Request ID':^20}>\n"
|
||||
f"<{request['id']:^20}>")
|
||||
orig_channel = ctx.guild.get_channel(int(request.get('channel')))
|
||||
comments_count_resp = await self.bot.aio_session.get(
|
||||
f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/{request["id"]}/comments/count/',
|
||||
headers=self.bot.auth_header)
|
||||
pag.add(f"\n\n{title}\n"
|
||||
f"{request['content']}\n\n"
|
||||
f"Comments: {await comments_count_resp.text() if comments_count_resp.status == 200 else 0}\n"
|
||||
f"Requested at: "
|
||||
f"{request['requested_at'].split('.')[0].replace('T', ' ')} GMT\n"
|
||||
f"In {orig_channel.name if orig_channel else 'N/A'}", keep_intact=True)
|
||||
pag.add(f'\n\uFFF8\nYou currently have {len(requests_list)} requests open.')
|
||||
else:
|
||||
pag.add('You have no open requests for this guild.', keep_intact=True)
|
||||
for page in pag.pages():
|
||||
await ctx.send(page)
|
||||
|
||||
@commands.command()
|
||||
async def close(self, ctx, *, ids=None):
|
||||
if not ids:
|
||||
await ctx.send('Please include at least one Request ID to close.')
|
||||
return
|
||||
|
||||
admin = False
|
||||
admin_roles_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/guilds/{ctx.guild.id}/roles/admin/',
|
||||
headers=self.bot.auth_header)
|
||||
if admin_roles_resp.status == 200:
|
||||
admin_roles_data = await admin_roles_resp.json()
|
||||
admin_roles = [ctx.guild.get_role(int(role['id'])) for role in admin_roles_data]
|
||||
if any([role in ctx.author.roles for role in admin_roles]):
|
||||
admin = True
|
||||
|
||||
ids = [id.strip() for id in ids.replace(' ', '').split(',')]
|
||||
|
||||
for id in ids:
|
||||
request_resp = await self.bot.aio_session.get(f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/{id}/', headers=self.bot.auth_header)
|
||||
if request_resp.status == 200:
|
||||
request = await request_resp.json()
|
||||
requestor = ctx.guild.get_member(int(request['author']))
|
||||
if requestor == ctx.author or admin:
|
||||
data = {
|
||||
'completed_by': ctx.author.id
|
||||
}
|
||||
delete_resp = await self.bot.aio_session.delete(f'{self.bot.api_base}/messages/{ctx.guild.id}/requests/{id}/', headers=self.bot.auth_header, json=data)
|
||||
if delete_resp.status == 202:
|
||||
delete_data = await delete_resp.json()
|
||||
if delete_data['completed']:
|
||||
await ctx.send(f'Request {id} closed.')
|
||||
await requestor.send(f'{ctx.author.display_name} has closed request {id} which was '
|
||||
f'opened by you in the '
|
||||
f'{ctx.guild.get_channel(int(request["channel"])).name} '
|
||||
f'channel.'
|
||||
f'```{request["content"]}```'
|
||||
f'If there are any issues please open a new request.')
|
||||
else:
|
||||
await ctx.send('That is not your request to close.')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Tickets(bot))
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import discord
|
||||
|
||||
|
||||
async def on_message(bot, message, user_info):
|
||||
if not user_info.get('disable_logging'):
|
||||
if message.guild:
|
||||
msg_data = {
|
||||
'author': str(message.author.id),
|
||||
'channel': str(message.channel.id),
|
||||
'mention_everyone': message.mention_everyone,
|
||||
'created_at': message.created_at
|
||||
}
|
||||
if message.mentions:
|
||||
msg_data['mentions'] = [str(user.id) for user in message.mentions]
|
||||
if message.channel_mentions:
|
||||
msg_data['channel_mentions'] = [str(channel.id) for channel in message.channel_mentions]
|
||||
if message.role_mentions:
|
||||
msg_data['role_mentions'] = [str(role.id) for role in message.role_mentions]
|
||||
if message.embeds:
|
||||
msg_data['embeds'] = [e.to_dict() for e in message.embeds]
|
||||
if message.content:
|
||||
msg_data['content'] = message.content
|
||||
if message.webhook_id:
|
||||
msg_data['webhook_id'] = message.webhook_id
|
||||
if message.tts:
|
||||
msg_data['tts'] = message.tts
|
||||
if message.attachments:
|
||||
msg_data['attachments'] = [{
|
||||
'id': str(a.id),
|
||||
'size': a.size,
|
||||
'filename': a.filename,
|
||||
'url': a.url
|
||||
} for a in message.attachments]
|
||||
|
||||
bot.fs_db.document(f'guilds/{message.guild.id}/messages/{message.id}').set(msg_data)
|
||||
else:
|
||||
msg_data = {
|
||||
'author': str(message.author.id),
|
||||
'created_at': message.created_at
|
||||
}
|
||||
if message.mentions:
|
||||
msg_data['mentions'] = [str(user.id) for user in message.mentions]
|
||||
if message.embeds:
|
||||
msg_data['embeds'] = [e.to_dict() for e in message.embeds]
|
||||
if message.content:
|
||||
msg_data['content'] = message.content
|
||||
if message.webhook_id:
|
||||
msg_data['webhook_id'] = message.webhook_id
|
||||
if message.tts:
|
||||
msg_data['tts'] = message.tts
|
||||
if message.attachments:
|
||||
msg_data['attachments'] = [{
|
||||
'id': str(a.id),
|
||||
'size': a.size,
|
||||
'filename': a.filename,
|
||||
'url': a.url
|
||||
} for a in message.attachments]
|
||||
|
||||
bot.fs_db.document(f'dm_channels/{message.channel.id}/messages/{message.id}').set(msg_data)
|
||||
|
||||
|
||||
async def on_message_edit(bot, before: discord.Message, after: discord.Message, user_config):
|
||||
if not user_config.get('disable_logging'):
|
||||
if after.guild:
|
||||
msg_ref = bot.fs_db.document(f'guilds/{after.guild.id}/messages/{after.id}')
|
||||
msg_data = (await bot.loop.run_in_executor(bot.tpe, msg_ref.get)).to_dict()
|
||||
if before.content != after.content:
|
||||
if before.content:
|
||||
if msg_data.get('previous_content') and isinstance(msg_data['previous_content'], list):
|
||||
msg_data['previous_content'].append(before.content)
|
||||
else:
|
||||
msg_data['previous_content'] = [before.content, ]
|
||||
msg_data['content'] = after.content
|
||||
if before.embeds != after.embeds:
|
||||
if before.embeds:
|
||||
if msg_data.get('previous_embeds') and isinstance(msg_data['previous_embeds'], list):
|
||||
msg_data['previous_embeds'].append(before.embeds[0].to_dict())
|
||||
else:
|
||||
msg_data['previous_embeds'] = [before.embeds[0].to_dict(), ]
|
||||
msg_data['embeds'] = [e.to_dict() for e in after.embeds]
|
||||
if before.pinned != after.pinned:
|
||||
msg_data['pinned'] = after.pinned
|
||||
if before.mentions != after.mentions:
|
||||
msg_data['mentions'] = [str(user.id) for user in after.mentions]
|
||||
if before.channel_mentions != after.channel_mentions:
|
||||
msg_data['channel_mentions'] = [str(user.id) for user in after.channel_mentions]
|
||||
if before.role_mentions != after.role_mentions:
|
||||
msg_data['role_mentions'] = [str(user.id) for user in after.role_mentions]
|
||||
if before.attachments != after.attachments:
|
||||
if before.attachments:
|
||||
if msg_data.get('previous_attachments') and isinstance(msg_data['previous_attachments'], list):
|
||||
msg_data['previous_attachments'].append([{
|
||||
'id': str(a.id),
|
||||
'size': a.size,
|
||||
'filename': a.filename,
|
||||
'url': a.url
|
||||
} for a in before.attachments])
|
||||
else:
|
||||
msg_data['previous_attachments'] = [[{
|
||||
'id': a.id,
|
||||
'size': a.size,
|
||||
'filename': a.filename,
|
||||
'url': a.url
|
||||
} for a in before.attachments], ]
|
||||
msg_data['attachments'] = [{
|
||||
'id': a.id,
|
||||
'size': a.size,
|
||||
'filename': a.filename,
|
||||
'url': a.url
|
||||
} for a in after.attachments]
|
||||
|
||||
bot.fs_db.document(f'guilds/{after.guild.id}/messages/{after.id}').set(msg_data)
|
||||
else:
|
||||
msg_ref = bot.fs_db.document(f'dm_channels/{after.channel.id}/messages/{after.id}')
|
||||
msg_data = (await bot.loop.run_in_executor(bot.tpe, msg_ref.get)).to_dict()
|
||||
if before.content != after.content:
|
||||
if before.content:
|
||||
if msg_data.get('previous_content') and isinstance(msg_data['previous_content'], list):
|
||||
msg_data['previous_content'].append(before.content)
|
||||
else:
|
||||
msg_data['previous_content'] = [before.content, ]
|
||||
msg_data['content'] = after.content
|
||||
if before.embeds != after.embeds:
|
||||
if before.embeds:
|
||||
if msg_data.get('previous_embeds') and isinstance(msg_data['previous_embeds'], list):
|
||||
msg_data['previous_embeds'].append(before.embeds[0].to_dict())
|
||||
else:
|
||||
msg_data['previous_embeds'] = [before.embeds[0].to_dict(), ]
|
||||
msg_data['embeds'] = [e.to_dict() for e in after.embeds]
|
||||
if before.pinned != after.pinned:
|
||||
msg_data['pinned'] = after.pinned
|
||||
if before.mentions != after.mentions:
|
||||
msg_data['mentions'] = [str(user.id) for user in after.mentions]
|
||||
if before.attachments != after.attachments:
|
||||
if before.attachments:
|
||||
if msg_data.get('previous_attachments') and isinstance(msg_data['previous_attachments'], list):
|
||||
msg_data['previous_attachments'].append([{
|
||||
'id': str(a.id),
|
||||
'size': a.size,
|
||||
'filename': a.filename,
|
||||
'url': a.url
|
||||
} for a in before.attachments])
|
||||
else:
|
||||
msg_data['previous_attachments'] = [[{
|
||||
'id': a.id,
|
||||
'size': a.size,
|
||||
'filename': a.filename,
|
||||
'url': a.url
|
||||
} for a in before.attachments], ]
|
||||
msg_data['attachments'] = [{
|
||||
'id': a.id,
|
||||
'size': a.size,
|
||||
'filename': a.filename,
|
||||
'url': a.url
|
||||
} for a in after.attachments]
|
||||
|
||||
bot.fs_db.document(f'dm_channels/{after.channel.id}/messages/{after.id}').set(msg_data)
|
||||
@@ -84,7 +84,8 @@ class Paginator:
|
||||
field_name_char: str = '\uFFF6',
|
||||
inline_char: str = '\uFFF5',
|
||||
max_line_length: int = 100,
|
||||
embed=False):
|
||||
embed=False,
|
||||
header: str = ''):
|
||||
_max_len = 6000 if embed else 1980
|
||||
assert 0 < max_lines <= max_chars
|
||||
|
||||
@@ -110,6 +111,7 @@ class Paginator:
|
||||
self._embed_thumbnail = None
|
||||
self._embed_url = None
|
||||
self._bot = bot
|
||||
self._header = header
|
||||
|
||||
def set_embed_meta(self, title: str = None,
|
||||
description: str = None,
|
||||
@@ -129,7 +131,7 @@ class Paginator:
|
||||
self._embed_thumbnail = thumbnail
|
||||
self._embed_url = url
|
||||
|
||||
def pages(self) -> typing.List[str]:
|
||||
def pages(self, page_headers: bool = True) -> typing.List[str]:
|
||||
_pages = list()
|
||||
_fields = list()
|
||||
_page = ''
|
||||
@@ -138,10 +140,16 @@ class Paginator:
|
||||
_field_value = ''
|
||||
_inline = False
|
||||
|
||||
def open_page():
|
||||
def open_page(initial: bool = False):
|
||||
nonlocal _page, _lines, _fields
|
||||
if not self._embed:
|
||||
_page = self._prefix
|
||||
if initial and not page_headers:
|
||||
_page = self._header
|
||||
elif page_headers:
|
||||
_page = self._header
|
||||
else:
|
||||
_page = ''
|
||||
_page += self._prefix
|
||||
_lines = 0
|
||||
else:
|
||||
_fields = list()
|
||||
@@ -156,7 +164,7 @@ class Paginator:
|
||||
_pages.append(_fields)
|
||||
open_page()
|
||||
|
||||
open_page()
|
||||
open_page(initial=True)
|
||||
|
||||
if not self._embed:
|
||||
for part in [str(p) for p in self._parts]:
|
||||
@@ -254,6 +262,9 @@ class Paginator:
|
||||
# noinspection PyProtectedMember
|
||||
return self.__class__ == other.__class__ and self._parts == other._parts
|
||||
|
||||
def set_header(self, header: str = ''):
|
||||
self._header = header
|
||||
|
||||
def add_page_break(self, *, to_beginning: bool = False) -> None:
|
||||
self.add(self._page_break, to_beginning=to_beginning)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user