-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathappbot.py
263 lines (236 loc) · 10.8 KB
/
appbot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
import discord
from discord.ext import commands
import asyncio
import speedtest
import requests
import hastebin
import itertools
import datetime
import aiohttp
import psutil
import logging
import time
import json
import os
with open('prefixes.json') as file:
prefixes = json.load(file)
def customprefix(bot, message):
try:
prefixlist = prefixes[str(message.guild.id)]
if os.path.basename(__file__) == 'appbotdev.py':
prefixlist.append('.')
return commands.when_mentioned_or(*prefixlist)(bot,message)
except:
return '/'
bot = commands.AutoShardedBot(command_prefix=customprefix,case_insensitive=True)
bot.remove_command('help')
import rethinkdb as r
bot.conn = r.connect(db="appbot")
db = r.table("guilds")
bot.db = r.table("guilds")
EMBEDCOLOR = 0x29b6f6
LOADINGEMOJI = '<a:loading:422579038918279169>'
YESEMOJI = '<:yes:426190071473897502>'
NOEMOJI = '<:no:426190098854445059>'
YESREACT = ':yes:426190071473897502'
NOREACT = ':no:426190098854445059'
start_time = time.time()
# DEFAULT = {"apps":{},"members":{},'DM':True, 'blacklist':[], 'logs': None, 'archives': None, 'appeditroles': [], 'appreviewroles': []}
# DATA FUNCTIONS
async def get_data(guild_id):
data = db.get(str(guild_id)).run(bot.conn)
if data is not None:
return data
else:
data = {"id":str(guild_id),"apps":{},"members":{},'DM':True, 'blacklist':[], 'logs': None, 'archives': None, 'appeditroles': [], 'appreviewroles': []}
db.insert(data).run(bot.conn)
return data
async def save_data(guild_id,data):
db.get(str(guild_id)).update(data).run(bot.conn)
# OTHER GLOBAL FUNCTIONS
def embed(title, description = None): return discord.Embed(title=title,description=description,color=EMBEDCOLOR)
def error(errormsg): return discord.Embed(title='An Error Occured',description=errormsg,color=0xff0000)
def getchannel(ctx, data):
if data['DM']:
return ctx.author
else:
return ctx
async def waitmsg(ctx, dm, obj=False):
def channel(message):
if dm:
return message.author == ctx.message.author and message.channel == message.author.dm_channel
else: return message.author == ctx.message.author and message.channel == ctx.message.channel
message = await bot.wait_for('message',check=channel,timeout=300.0)
if obj:
return message
else:
return message.content
async def waitrct(ctx, message, reactions):
def rctcheck(reaction,user):
return reaction.message.id == message.id and user == ctx.message.author and str(reaction.emoji) in reactions
reaction, user = await bot.wait_for('reaction_add',timeout=300.0,check=rctcheck)
return str(reaction.emoji)
async def getnum(ctx, data, min, max): #Getting a number within a provided range
global channel
user = getchannel(ctx, data)
def channel(message):
if data['DM']:
return message.author == ctx.message.author and message.channel == message.author.dm_channel
else: return message.author == ctx.message.author and message.channel == ctx.message.channel
while True:
anum = await bot.wait_for('message',check=channel,timeout=600.0)
try:
anum = int(anum.content)
if min <= anum <= max:
return anum
else:
await user.send(embed=error(f'Please enter a valid question number in within {min} and {max}.'))
except:
await user.send(embed=error('Please enter a number.'))
async def areyousure(ctx, data, suredesc):
global channel
areyousure = await getchannel(ctx, data).send(embed=embed("Are you sure?",suredesc))
for reaction in [YESREACT,NOREACT]:
await areyousure.add_reaction(reaction)
reaction = await waitrct(ctx, areyousure, [YESEMOJI,NOEMOJI])
if reaction == YESEMOJI:
return True
else: return False
async def getapp(ctx, data):
user = getchannel(ctx, data)
if len(data['apps']) == 1:
appnum = 1
else:
whichapp = embed('Select an Application','Select an application to continue.')
appnum = 0
for app, appdata in data['apps'].items():
appnum += 1
if appdata['open']:
status = 'Open'
else: status = 'Closed'
whichapp.add_field(name=str(appnum) + '. ' + app,value=f"Type: {appdata['type']}\nTotal Questions: {len(appdata['app'])}\nStatus: {status}")
await user.send(embed = whichapp)
appnum = await getnum(ctx, data, 1, len(data['apps']))
return list(data['apps'].keys())[appnum - 1] # Returns the App Name
async def cancel(text):
if text.lower() == 'cancel':
return True
else: return False
async def log(ctx, data, action, description):
log_id = data['logs']
if log_id is None: return
logchannel = bot.get_channel(int(log_id))
if logchannel is None: return await ctx.author.send(embed=error("The bot was unable to log an action. Please resolve this issue as soon as possible."))
try: await logchannel.send(embed=discord.Embed(title=action, description=description, color=EMBEDCOLOR, timestamp=datetime.datetime.utcnow()))
except: await ctx.author.send(embed=error("The bot was unable to log an action. Please resolve this issue as soon as possible."))
def has_perms(ctx, data, permtype :int): # 0 = no perms, 1 = review perms, 2 = config perms
if permtype not in [0, 1, 2]: return print('INVALID PERMTYPE')
if ctx.author.guild_permissions.administrator:
return True
for role in ctx.author.roles:
if str(role.id) in data['appeditroles']:
if permtype is 2:
return True
if str(role.id) in data['appreviewroles']:
if permtype is 1:
return True
return False
def create_gist(q, a):
data = requests.post(
"https://api.github.com/gists",
json = {
"description": "AppBot - a Discord bot made for staff application management within Discord.",
"public": True,
"files": {
"answer.md": {
"content": f"# {q}\n#### {a}"
}
}
},
headers = {
'Content-Type' : 'application/json',
"Authorization": "token e03nfsdl49g0fvajsdkf2j4i9340rwkejf2q0w0eo9"
}
)
data = json.loads(data.content.decode('utf-8')) # Convert bytes to str, str to json
gist_id = data['html_url'][24:]
return gist_id
bot.session = aiohttp.ClientSession(loop=bot.loop)
startup_extensions = [
"main.administrator",
"main.reviewer",
"main.members",
"sub.error handler",
"sub.post servers",
"sub.eval",
"sub.other"
]
for extension in startup_extensions:
try:
bot.load_extension(extension)
except Exception as e:
exc = f"{type(e).__name__}: {e}"
print(f'Failed to load extension {extension}\n{exc}')
bot.data = get_data
bot.save = save_data
bot.getchannel = getchannel
bot.prefixes = prefixes
bot.waitmsg = waitmsg
bot.waitrct = waitrct
bot.getnum = getnum
bot.sure = areyousure
bot.has_perms = has_perms
bot.log = log
bot.create_gist = create_gist
bot.get_app = getapp
bot.cancel = cancel
@bot.event
async def on_ready():
os.system("clear")
print("\n\n████████████████████████████████████████████████████████\n")
print(" ______ _____ __ ")
print("/\ _ \ /\ __`\ /\ \__ ")
print("\ \ \L\ \ _____ _____\ \ \L\ \ ___\ \ ,_\ ")
print(" \ \ __ \/\ '__`\/\ '__`\ \ _ <' / __`\ \ \/ ")
print(" \ \ \/\ \ \ \L\ \ \ \L\ \ \ \L\ \/\ \L\ \ \ \_ ")
print(" \ \_\ \_\ \ ,__/\ \ ,__/\ \____/\ \____/\ \__\ ")
print(" \/_/\/_/\ \ \/ \ \ \/ \/___/ \/___/ \/__/ ")
print(" \ \_\ \ \_\ ")
print(" \/_/ \/_/ AppBot 2.0 - 2x more bugs ")
print("\n████████████████████████████████████████████████████████\n\n")
@bot.event
async def on_guild_join(guild):
await guild.owner.send(embed=embed('Thank you for adding AppBot!','Thank you for adding AppBot, the most feature-packed bot made for applications built into Discord!\n\nReady to get started?\nType `/config` to create your first application.\n\nWhat\'s next?\nType `/config` after setting up your first application to access a menu which allows you to add more applications, set a log channel, change the prefix, and much more.\n\nIf you require more assistance, please join the [support server](https://www.appbot.gq/support).'))
@bot.event
async def on_message(message):
appbotguild = discord.utils.get(bot.guilds, id = 423374132873527297)
ctx = await bot.get_context(message)
if ctx.valid:
if ctx.author.bot: return
if not bot.is_ready(): return await message.channel.send(embed=error("The bot is still starting up. Please wait patiently."))
await bot.invoke(ctx)
@bot.event
async def on_member_remove(member):
data = await get_data(member.guild.id)
if str(member.id) in data['members']:
db.get(str(member.guild.id)).replace(r.row.without({'members':{str(member.id):True}})).run(bot.conn)
async def presence():
await bot.wait_until_ready()
cycle = ['apps for {} users'.format(len(bot.users)),'apps for {} servers'.format(len(bot.guilds)),f'for @AppBot help']
statusnum = 0
while not bot.is_closed():
await bot.change_presence(activity=discord.Activity(name=cycle[statusnum],type=discord.ActivityType.watching))
statusnum += 1
if statusnum == 2: statusnum = 0
await asyncio.sleep(30)
bot.loop.create_task(presence())
#███████████████████████████████████████ Startup █████████████████████████████████████████
#███████████████ 🔽 Main Bot 🔽 ████████████████████
if os.path.basename(__file__) == 'appbot.py':
bot.run(MAIN_BOT_TOKEN)
elif os.path.basename(__file__) == 'appbotdev.py':
bot.run(TEST_BOT_TOKEN)
else:
print("This file must be called \"appbot.py\" or \"appbotdev.py\". Connection closed.")
#███████████████ 🔼 Test Bot 🔼 ████████████████████
#█████████████████████████████████████████████████████████████████████████████████████████