Skip to content

Commit 09bfc6b

Browse files
committed
Rename to core
1 parent 4c3f717 commit 09bfc6b

File tree

3 files changed

+524
-0
lines changed

3 files changed

+524
-0
lines changed

core/api.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import discord
2+
import secrets
3+
4+
from hashlib import sha256
5+
6+
class ApiClient:
7+
def __init__(self, app):
8+
self.app = app
9+
self.session = app.session
10+
self.headers = None
11+
12+
async def request(self, url, method='GET', payload=None):
13+
async with self.session.request(method, url, headers=self.headers, json=payload) as resp:
14+
try:
15+
return await resp.json()
16+
except:
17+
return await resp.text()
18+
19+
class Github(ApiClient):
20+
commit_url = 'https://api.github.com/repos/kyb3r/modmail/commits'
21+
22+
async def get_latest_commits(self, limit=3):
23+
resp = await self.request(self.commit_url)
24+
for index in range(limit):
25+
yield resp[index]
26+
27+
28+
class ModmailApiClient(ApiClient):
29+
30+
base = 'https://api.modmail.tk'
31+
github = base + '/github'
32+
logs = base + '/logs'
33+
34+
def __init__(self, bot):
35+
super().__init__(bot)
36+
self.token = bot.config.get('MODMAIL_API_TOKEN')
37+
if self.token:
38+
self.headers = {
39+
'Authorization': 'Bearer ' + self.token
40+
}
41+
42+
def get_user_info(self):
43+
return self.request(self.github + '/userinfo')
44+
45+
def update_repository(self):
46+
return self.request(self.github + '/update-repository')
47+
48+
def get_metadata(self):
49+
return self.request(self.base + '/metadata')
50+
51+
def get_user_logs(self, user_id):
52+
return self.request(self.logs + '/user/' + str(user_id))
53+
54+
def get_log(self, channel_id):
55+
return self.request(self.logs + '/' + str(channel_id))
56+
57+
def get_log_url(self, recipient, channel, creator):
58+
return self.request(self.logs + '/key', payload={
59+
'channel_id': str(channel.id),
60+
'guild_id': str(self.app.guild_id),
61+
'recipient': {
62+
'id': str(recipient.id),
63+
'name': recipient.name,
64+
'discriminator': recipient.discriminator,
65+
'avatar_url': recipient.avatar_url,
66+
'mod': False
67+
},
68+
'creator': {
69+
'id': str(creator.id),
70+
'name': creator.name,
71+
'discriminator': creator.discriminator,
72+
'avatar_url': creator.avatar_url,
73+
'mod': isinstance(creator, discord.Member)
74+
}
75+
})
76+
77+
def append_log(self, message, channel_id=''):
78+
channel_id = str(channel_id) or str(message.channel.id)
79+
payload = {
80+
'payload': {
81+
'timestamp': str(message.created_at),
82+
'message_id': str(message.id),
83+
# author
84+
'author': {
85+
'id': str(message.author.id),
86+
'name': message.author.name,
87+
'discriminator': message.author.discriminator,
88+
'avatar_url': message.author.avatar_url,
89+
'mod': not isinstance(message.channel, discord.DMChannel),
90+
},
91+
# message properties
92+
'content': message.content,
93+
'attachments': [i.url for i in message.attachments]
94+
}
95+
}
96+
return self.request(self.logs + f'/{channel_id}', method='PATCH', payload=payload)
97+
98+
def post_log(self, channel_id, payload):
99+
return self.request(self.logs + f'/{channel_id}', method='POST', payload=payload)

core/paginator.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import discord
2+
from discord.ext import commands
3+
from collections import OrderedDict
4+
import asyncio
5+
import inspect
6+
7+
class PaginatorSession:
8+
'''
9+
Class that interactively paginates a set of embeds
10+
11+
Parameters
12+
------------
13+
ctx: Context
14+
The context of the command.
15+
timeout:
16+
How long to wait for before the session closes
17+
embeds: List[discord.Embed]
18+
A list of entries to paginate.
19+
20+
Methods
21+
-------
22+
add_page:
23+
Add an embed to paginate
24+
run:
25+
Run the interactive session
26+
close:
27+
Forcefully destroy a session
28+
'''
29+
def __init__(self, ctx, *embeds, **options):
30+
self.ctx = ctx
31+
self.timeout = options.get('timeout', 60)
32+
self.embeds = embeds
33+
self.running = False
34+
self.base = None
35+
self.current = 0
36+
self.reaction_map = {
37+
'⏮': self.first_page,
38+
'◀': self.previous_page,
39+
'▶': self.next_page,
40+
'⏭': self.last_page,
41+
# '⏹': self.close
42+
}
43+
44+
if options.get('edit_footer', True) and len(self.embeds) > 1:
45+
for i, em in enumerate(self.embeds):
46+
footer_text = f'Page {i+1} of {len(self.embeds)}'
47+
if em.footer.text:
48+
footer_text = footer_text + ' • ' + em.footer.text
49+
em.set_footer(text=footer_text, icon_url=em.footer.icon_url)
50+
51+
52+
def add_page(self, embed):
53+
if isinstance(embed, discord.Embed):
54+
self.embeds.append(embed)
55+
else:
56+
raise TypeError('Page must be an Embed object.')
57+
58+
async def create_base(self, embed):
59+
self.base = await self.ctx.send(embed=embed)
60+
61+
if len(self.embeds) == 1:
62+
self.running = False
63+
return
64+
65+
self.running = True
66+
for reaction in self.reaction_map.keys():
67+
if len(self.embeds) == 2 and reaction in '⏮⏭':
68+
continue
69+
await self.base.add_reaction(reaction)
70+
71+
async def show_page(self, index: int):
72+
if not 0 <= index < len(self.embeds):
73+
return
74+
75+
self.current = index
76+
page = self.embeds[index]
77+
78+
if self.running:
79+
await self.base.edit(embed=page)
80+
else:
81+
await self.create_base(page)
82+
83+
def react_check(self, reaction, user):
84+
return user.id == self.ctx.author.id and reaction.emoji in self.reaction_map.keys()
85+
86+
async def run(self):
87+
if not self.running:
88+
await self.show_page(0)
89+
while self.running:
90+
try:
91+
reaction, user = await self.ctx.bot.wait_for('reaction_add', check=self.react_check, timeout=self.timeout)
92+
except asyncio.TimeoutError:
93+
self.paginating = False
94+
await self.close(delete=False)
95+
else:
96+
action = self.reaction_map.get(reaction.emoji)
97+
await action()
98+
try:
99+
await self.base.remove_reaction(reaction, user)
100+
except:
101+
pass
102+
103+
104+
def previous_page(self):
105+
'''Go to the previous page.'''
106+
return self.show_page(self.current-1)
107+
108+
def next_page(self):
109+
'''Go to the next page'''
110+
return self.show_page(self.current+1)
111+
112+
async def close(self, delete=True):
113+
'''Delete this embed.'''
114+
self.running = False
115+
116+
try:
117+
await self.ctx.message.add_reaction('✅')
118+
except:
119+
pass
120+
121+
if delete:
122+
return await self.base.delete()
123+
124+
try:
125+
await self.base.clear_reactions()
126+
except:
127+
pass
128+
129+
def first_page(self):
130+
'''Go to immediately to the first page'''
131+
return self.show_page(0)
132+
133+
def last_page(self):
134+
'''Go to immediately to the last page'''
135+
return self.show_page(len(self.embeds)-1)

0 commit comments

Comments
 (0)