-
Notifications
You must be signed in to change notification settings - Fork 2
/
echo.py
228 lines (208 loc) · 10.6 KB
/
echo.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
import re
import discord
from discord.ext import commands
import menus
import missile
from sql import Quote
def split_quoter(quoter: str):
quoter = re.split(r" *, *", quoter)
return quoter[0], quoter[1] if len(quoter) > 1 else None
async def verify_quoter(ctx, quoter, quoter_group):
if quoter_group:
if '<@' in quoter_group:
await ctx.reply('You can only mention a user as a quoter, but not a quoter group.')
raise commands.errors.CheckFailure
if '\n' in quoter or '\n' in quoter_group:
await ctx.reply('Quoter must be single line!')
raise commands.errors.CheckFailure
class Bottas(commands.Cog):
"""Storing messages.
Version 3.2.1"""
def __init__(self, bot):
self.bot = bot
@commands.group(invoke_without_command=True)
async def quote(self, ctx, index: int = 0):
"""
Commands for interacting with quotes.
`quote [subcommand | ID]`
If no subcommand is provided, it takes an optional argument which is the ID of a quote and displays it.
If no quote ID or quote ID is invalid, shows a random quote.
"""
count = await self.bot.sql.get_quotes_count(self.bot.db)
if await self.bot.sql.quote_id_exists(self.bot.db, id=index):
await menus.QuoteMenu(index, count).start(ctx)
else:
index = await self.bot.sql.get_random_id(self.bot.db)
await menus.QuoteMenu(index[0], count).start(ctx)
@quote.command(aliases=('q',), brief='Search quote by quoter')
async def quoter(self, ctx, *, quoter_msg):
"""`quote q [quoter][, ][quoter group]`
Quoter, quoter group: A sentence. The name of the quoter/quoter group.
Please note that for `[quoter]` you can mention a User to achieve the same result as `quote d @user`.
"""
quoter, quoter_group = split_quoter(quoter_msg)
quotes = await self.bot.sql.get_quoter_quotes(self.bot.db, quoter=quoter, QuoterGroup=quoter_group)
if quotes:
quotes = tuple(map(lambda q: Quote(*q), quotes))
await menus.QuotesMenu(quotes).start(ctx)
else:
await ctx.reply(f'There are no quotes by **{quoter_msg}**!')
@quote.command(name='discord', aliases=('d',), brief='Search quote by a Discord user, similar to quoter')
async def discord_user(self, ctx, quoter: discord.User, quoter_group: str = None):
"""`quote d <quoter> [quoter group]`
Quoter: A Discord user.
group: A string for filtering the results by quoter group.
Please note that you don't necessarily have to mention the User for quoter.
"""
quotes = await self.bot.sql.get_quoter_quotes(self.bot.db, quoter=quoter.mention, QuoterGroup=quoter_group)
if quotes:
quotes = tuple(map(lambda q: Quote(*q), quotes))
await menus.QuotesMenu(quotes).start(ctx)
else:
await ctx.reply(f'There are no quotes by **{quoter}{", " + quoter_group if quoter_group else ""}**!')
@quote.command(aliases=('u',), brief='List quotes uploaded by a Discord user')
async def uploader(self, ctx, user: discord.User = None):
"""`quote u [user]`
user: The user to filter with
"""
user = user if user else ctx.author
quotes = await self.bot.sql.get_uploader_quotes(self.bot.db, uid=user.id)
if quotes:
quotes = tuple(map(lambda q: Quote(*q), quotes))
await menus.QuotesMenu(quotes).start(ctx)
else:
await ctx.reply(f'There are no quotes uploaded by **{user}**!')
@quote.command(name='add', aliases=('a',), brief='Adds a quote')
async def quote_add(self, ctx: commands.Context, *, quote):
"""d.quote a <quote>
quote: The new quote to be added
"""
# Check if a quote with the same content already exists in the database
rowid = await self.bot.sql.quote_msg_exists(self.bot.db, msg=quote)
if rowid:
await ctx.send(f'This quote duplicates with #{rowid}')
return
# Asks for the quoter who said the quote
quoter = await self.bot.ask_msg(ctx, 'Quoter?')
if quoter:
quoter, quoter_group = split_quoter(quoter)
await verify_quoter(ctx, quoter, quoter_group) # Quoter validation
if quoter.startswith('<@!') and quoter.endswith('>'):
quoter.replace('!', '')
# Determines the ROWID to be used for inserting the quote
rowid = await self.bot.sql.get_next_row_id(self.bot.db)
if rowid: # Use ROWID from QuoteRowID if available. These IDs exist when a quote was deleted
last_row_id = await self.bot.sql.add_quote_with_rowid(
self.bot.db, rowid=rowid, msg=quote, quoter=quoter, uid=ctx.author.id, QuoterGroup=quoter_group,
time=ctx.message.created_at
)
await self.bot.sql.delete_rowid(self.bot.db, id=rowid)
else: # Normal insertion, using an all new ROWID
last_row_id = await self.bot.sql.add_quote(
self.bot.db, msg=quote, quoter=quoter, uid=ctx.author.id, QuoterGroup=quoter_group,
time=ctx.message.created_at
)
await ctx.send(f"Added quote #{last_row_id}")
@quote.command(name='delete', aliases=('del',), brief='Deletes a quote')
async def quote_delete(self, ctx, index: int):
"""quote del <index>
index: The ID of the quote
"""
quote = await self.bot.sql.get_quote(self.bot.db, id=index)
if quote: # Checks if the quote exists
quote = Quote(index, *quote)
# Check if sender is quote uploader or sender is me (db admin)
if quote.uid == ctx.author.id or ctx.author.id == self.bot.owner_id:
# Confirmation
if await self.bot.ask_reaction(ctx, f"> {quote.msg}\n"
f"You sure you want to delete this? React ✅ to confirm"):
# Delete
await self.bot.sql.delete_quote(self.bot.db, id=index)
await self.bot.sql.add_next_rowid(self.bot.db, id=index)
await ctx.send('Deleted quote.')
else:
await ctx.send("You must be the quote uploader to delete the quote!")
else:
await ctx.send('No quote found!')
@quote.command(aliases=('m',), brief='Filter quotes by keyword')
async def message(self, ctx: commands.Context, *, keyword):
"""quote m <keyword>
keyword: The sentence that the quotes must contain. Case insensitive."""
quotes = await self.bot.sql.get_keyword_quotes(self.bot.db, kw=f'%{keyword}%')
if quotes:
quotes = tuple(map(lambda q: Quote(*q), quotes))
await menus.QuotesMenu(quotes).start(ctx)
else:
await ctx.reply(f'There are no quotes with the keyword **{keyword}**!')
@quote.command(aliases=('e',), brief='Edits a quote')
async def edit(self, ctx: commands.Context, index: int):
"""quote e <index>
index: The ID of the quote to edit.
"""
quote = await self.bot.sql.get_quote(self.bot.db, id=index)
if quote and (quote[2] == ctx.author.id or ctx.author.id == self.bot.owner_id):
quote = Quote(index, *quote)
content = await self.bot.ask_msg(ctx, 'Enter the new quote: (wait 10 seconds if it is the same)')
if not content:
content = quote.msg
quoter = await self.bot.ask_msg(ctx, "Enter new quoter: (wait 10 seconds if it is the same)")
if quoter:
quoter, quoter_group = split_quoter(quoter)
await verify_quoter(ctx, quoter, quoter_group) # Quoter validation
else:
quoter = quote.quoter
quoter_group = quote.quoter_group
await self.bot.sql.update_quote(
self.bot.db, msg=content, quoter=quoter, QuoterGroup=quoter_group, id=index
)
await ctx.reply('Quote updated')
else:
await ctx.reply("You can't edit this quote!")
@commands.group(
invoke_without_command=True,
brief='Commands related to tags. It can also be used as a command itself, with a single string argument.')
async def tag(self, ctx: commands.Context, name: str = ''):
"""
If a subcommand is provided, runs the subcommand.
If the provided argument is not a subcommand, it shows the content of the provided tag.
If no arguments are provided, lists all tags within the server."""
if name:
content = await self.bot.sql.get_tag_content(self.bot.db, name=name, guildID=ctx.guild.id)
if content:
ref_msg = missile.MsgRefIter.get_ref_msg(ctx.message)
if ref_msg:
await ref_msg.reply(content[0])
else:
await ctx.reply(content[0])
else:
await ctx.reply(f"Tag `{name}` not found.")
else:
async with self.bot.sql.get_tags_name_cursor(self.bot.db, guildID=ctx.guild.id) as cursor:
msg = ''
async for row in cursor:
msg += row[0] + ', '
await ctx.reply(f"`{msg[:-2]}`")
@tag.command(name='add', aliases=('a',), brief='Adds a tag')
@commands.has_permissions(manage_messages=True)
async def tag_add(self, ctx: commands.Context, name: str, url: str):
"""tag a <name> <url>"""
if not missile.is_url(url):
await ctx.reply('Tag content must be a HTTP WWW link!')
return
if '<@' in name:
await ctx.reply('Why are you mentioning people in tag names?')
return
if await self.bot.sql.tag_exists(self.bot.db, name=name, content=url, guildID=ctx.guild.id):
await ctx.reply('A tag with the same name/link already exists!')
return
await self.bot.sql.add_tag(self.bot.db, name=name, content=url, guildID=ctx.guild.id)
await ctx.reply('Your tag has been created!')
@tag.command(name='delete', aliases=('d',), brief='Deletes a tag')
@commands.has_permissions(manage_messages=True)
async def tag_delete(self, ctx: commands.Context, name: str):
"""tag d <name>"""
if await self.bot.sql.tag_name_exists(self.bot.db, name=name, guildID=ctx.guild.id):
await self.bot.sql.delete_tag(self.bot.db, name=name, guildID=ctx.guild.id)
await ctx.reply('Deleted tag.')
else:
await ctx.reply(f"Tag `{name}` not found.")