-
Notifications
You must be signed in to change notification settings - Fork 2
/
tribe.py
232 lines (201 loc) · 11.3 KB
/
tribe.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
import asyncio
from sqlite3 import IntegrityError
from typing import Optional
import discord
from discord.ext.commands import Context, group, has_guild_permissions
import missile
from missile import Cog
guild_id = 285366651312930817
async def solo_vc(vc):
await asyncio.sleep(vc.guild.afk_timeout)
if len(vc.members) == 1:
await vc.members[0].move_to(None)
class Hamilton(Cog):
"""Per-guild features, Guild/user settings
Version 2.1"""
def __init__(self, bot: missile.Bot):
super().__init__(bot, 'Hamilton')
self.invites = {}
self.guild = bot.get_guild(guild_id) # My own server
self.logs = bot.get_channel(384636771805298689) # #logs in my server
self.bot_test = bot.get_channel(666431254312517633) # #bot_test
async def get_join_invite(self) -> discord.Invite:
"""Returns the invite used by a member.This is done by first caching self.invites in on_ready() then compare
each invite count on on_member_join()"""
invites = await self.get_invites_dict()
for code in invites:
if code in self.invites:
if invites[code] != self.invites[code]:
self.invites = invites
return code
elif invites[code]:
self.invites = invites
return code
async def get_invites_dict(self) -> dict:
invites = await self.guild.invites()
d = {}
for invite in invites:
d[invite.code] = invite.uses
return d
@Cog.listener()
async def on_ready(self):
self.invites = await self.get_invites_dict() # Caches invites
@Cog.listener()
async def on_message(self, msg: discord.Message):
if msg.guild and msg.content == self.bot.user.mention:
p = await self.bot.get_prefix(msg)
if p == self.bot.default_prefix:
await msg.channel.send(f'My prefix is **{self.bot.default_prefix}**')
else:
await msg.channel.send(f"My prefixes are **{'**, **'.join(p)}**")
@Cog.listener()
async def on_member_join(self, member: discord.Member):
if member.guild == self.guild: # Only activates if its in my server
invite = await self.get_join_invite()
await self.logs.send(f"{member.mention} ({member}) joined via code `{invite}`")
if invite == 'g6Yrteq': # Joined via BBM invite
role = self.guild.get_role(664210105318768661)
await member.add_roles(role)
ch = self.bot.get_channel(372386868236386307) # Bottyland
await ch.send(
f'Welcome {member.mention}! You are automatically added to the role {role.name} '
f'for related announcements.'
f' If you wish to unsubscribe, please send `d.role {role.name}` in {ch.mention}.'
)
# No longer works due to outdated discord.py
@Cog.listener()
async def on_member_left(self, member: discord.Member):
if member.guild == self.guild:
await self.logs.send(f'{member.mention} has left.')
@Cog.listener()
async def on_voice_state_update(self, m: discord.Member, before, after: discord.VoiceState):
"""Anti AFK & Invisible"""
if await self.bot.sql.get_anti_invisible(self.bot.db, guild=m.guild.id) and \
after.channel and m.status == discord.Status.offline:
await m.send(f"Please don't set your status as invisible while online in {m.guild.name} :)")
if before.channel and len(before.channel.members) == 1 and not after.channel \
and before.channel.guild.me.guild_permissions.move_members:
await solo_vc(before.channel)
elif after.channel and after.channel.guild.me.guild_permissions.move_members: # Joined a VC
if after.afk and after.channel.type == discord.ChannelType.voice:
await m.move_to(None) # Joined AFK VC
elif len(after.channel.members) == 1:
await solo_vc(after.channel)
@Cog.listener()
async def on_typing(self, channel, user, when):
"""I hate people being invisible"""
if channel.type == discord.ChannelType.text and \
await self.bot.sql.get_anti_invisible(self.bot.db, guild=user.guild.id) and \
user.status == discord.Status.offline:
await user.send(f"Please don't set your status as invisible while online in {user.guild.name} :)")
@Cog.listener()
async def on_guild_join(self, guild: discord.Guild):
await self.bot_test.send(f'Joined server {guild.id} {guild.name} <@{self.bot.owner_id}>')
if await self.bot.sql.is_guild_banned(self.bot.db, id=guild.id):
await guild.leave()
return
await self.bot.sql.add_guild_cfg(self.bot.db, guildID=guild.id)
if guild.me.guild_permissions.change_nickname:
await guild.me.edit(nick=self.bot.nickname)
@Cog.listener()
async def on_guild_remove(self, guild: discord.Guild):
await self.bot_test.send(f'Left server {guild.id} {guild.name}')
@Cog.listener()
async def on_guild_role_delete(self, role: discord.Role):
await self.bot.sql.remove_joinable_role(self.bot.db, role=role.id)
@group()
@missile.guild_only()
@has_guild_permissions(manage_guild=True)
async def guild(self, ctx: Context):
"""Settings for server"""
await self.send_grp_cmd_help(ctx)
@guild.command(brief='Changes the custom prefix of DimBot')
async def prefix(self, ctx: Context, *, p: str = None):
"""`guild prefix [p]`
`p` is a SENTENCE so you can send like `Super bad prefix` as `p` without quotation marks.
Note that d. will still work. Send the command without arguments to remove the custom prefix."""
if p and p.startswith(ctx.bot.user.mention):
await ctx.reply('Prefix cannot start with pinging me!')
else:
await self.bot.sql.update_guild_prefix(self.bot.db, guildID=ctx.guild.id, prefix=p)
await ctx.reply('Updated server prefix.')
@guild.command(brief='Sets the moderation role of the server')
async def modrole(self, ctx: Context, role: discord.Role):
"""guild modrole <role>"""
await self.bot.sql.set_mod_role(self.bot.db, role=role.id, guild=ctx.guild.id)
await ctx.reply('Updated moderation role to ' + role.name)
@guild.command(brief='Sets snipe discovery for the server')
async def snipe(self, ctx: Context, level: int = 2):
"""This command sets whether snipes can work and whether they are visible in other servers.
0: Snipe/GSnipe will not detect deleted messages in this server at all.
1: Snipe will detect but the detected messages are only visible in this server (`gsnipe` won't display)
2 (default): Snipe will detect and they are visible in other servers (`gsnipe` can display this server's snipes)"""
if 0 <= level <= 2:
await self.bot.sql.set_snipe_cfg(self.bot.db, snipe=level, guild=ctx.guild.id)
await ctx.reply('Updated snipe discovery level')
else:
await ctx.reply(
f'Invalid discovery level! Please send `{await self.bot.get_prefix(ctx.message)}help guild snipe`!')
@guild.command(brief='Toggles auto kicking members from VC when they afk')
async def antiafk(self, ctx: Context, enable: bool = True):
"""guild antiafk [enable]
enable: Whether to enable the feature or not. Defaults to yes."""
await self.bot.sql.set_anti_afk(self.bot.db, antiafk=enable, guild=ctx.guild.id)
await ctx.reply('Updated!')
@guild.command(aliases=('invis', 'invi'), brief='Toggles anti invisible feature')
async def invisible(self, ctx: Context, enable: bool = False):
"""guild invisible [enable]
enable: Whether to enable the feature or not. Defaults to no."""
await self.bot.sql.set_anti_invisible(self.bot.db, invisible=enable, guild=ctx.guild.id)
await ctx.reply('Updated!')
@guild.command(brief='Sets a joinable role')
async def setjr(self, ctx: Context, role: discord.Role, required_role: Optional[discord.Role],
check_highest: bool = True):
"""`guild setjr <role> [required role] [check highest]`
role: The joinable role that is to be modified/added
required role: The optional required role that is needed to join this role. You can literally skip this argument
check highest: Whether only allows to join role if the role is at a lower position then the sender's
highest role"""
required = required_role.id if required_role else None
if await self.bot.sql.get_joinable_role(self.bot.db, role.id):
await self.bot.sql.update_joinable_role(self.bot.db, role=role.id, required=required,
checkHighest=check_highest)
else:
await self.bot.sql.add_joinable_role(self.bot.db, role=role.id, required=required,
checkHighest=check_highest)
await ctx.reply(embed=missile.Embed(description=f"""Joinable role: {role.mention}
Required role: {required_role.mention if required_role else 'None'}
Check highest role: {check_highest}"""))
@guild.command(brief='Deletes a joinable role')
async def deljr(self, ctx: Context, role: discord.Role):
"""`guild deljr <role>
role: The joinable role to be removed from the database"""
await self.bot.sql.remove_joinable_role(self.bot.db, role=role.id)
await ctx.reply('Deleted')
@guild.command()
async def roleping(self, ctx: Context, role: discord.Role):
if role.is_default() or role.is_premium_subscriber():
await ctx.reply('The role cannot be the default role or Nitro role')
else:
resp = 'The role is no longer pingable by its members'
try:
await self.bot.sql.add_role_ping(self.bot.db, role=role.id)
resp = 'The role is now pingable by its members'
except IntegrityError:
await self.bot.sql.remove_role_ping(self.bot.db, role=role.id)
await ctx.reply(resp)
@group(brief='Settings for a user')
async def user(self, ctx: Context):
await self.send_grp_cmd_help(ctx)
@user.command(brief="Sets a user's preferred language")
async def lang(self, ctx: Context):
locale_msg = await self.bot.ask_msg(ctx,
'Please reply this message with the ID of your preferred language, '
'e.g. `en_US`, `ja`, `zh_hant_HK`. See <https://localeplanet.com/icu/>',
None,
return_msg_obj=True)
try:
await self.bot.sql.add_user_lang(self.bot.db, user=ctx.author.id, locale=locale_msg.content)
except IntegrityError:
await self.bot.sql.update_user_lang(self.bot.db, user=ctx.author.id, locale=locale_msg.content)
await locale_msg.add_reaction('👍')