Skip to content
This repository has been archived by the owner on Dec 4, 2022. It is now read-only.

Commit

Permalink
3.3.1 release
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMoksej committed Dec 18, 2021
1 parent 19768dd commit 9f955a8
Show file tree
Hide file tree
Showing 21 changed files with 1,156 additions and 365 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

- [Install node.js](https://nodejs.org/en/download/) **Required if you want to use pm2**
- [Install PostgreSQL](https://www.postgresql.org/download/windows/)
- [Install Python 3.5+](https://www.python.org/downloads/)
- [Install Python 3.8+ < 3.10](https://www.python.org/downloads/)
- [Install pm2](https://pm2.keymetrics.io/docs/usage/quick-start/) **Required if you want to use pm2**
- Create a PostgreSQL database & all the tables
- Install all the requirements through pip `pip install -r requirements.txt`
Expand All @@ -15,7 +15,7 @@

- [Install node.js](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions) **Required if you want to use pm2**
- [Install PostgreSQL](https://www.postgresql.org/download/linux/)
- [Install Python 3.5+](https://opensource.com/article/20/4/install-python-linux)
- [Install Python 3.8+ < 3.10](https://opensource.com/article/20/4/install-python-linux)
- [Install pm2](https://pm2.keymetrics.io/docs/usage/quick-start/) **Required if you want to use pm2**
- Create a PostgreSQL database & all the tables
- Install all the requirements through pip `pip install -r requirements.txt`
Expand Down
14 changes: 11 additions & 3 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

from discord.ext import commands

from db.cache import LoadCache, CacheManager, DreddUser, DreddGuild
from db.cache import LoadCache, CacheManager, DreddUser, DreddGuild, Database as postgres, ReactionRoles
from utils import i18n
from collections import Counter
from typing import Optional, Union, Any
Expand All @@ -44,8 +44,7 @@
async def run():
description = "A bot written in Python that uses asyncpg to connect to a postgreSQL database."

# NOTE: 127.0.0.1 is the loopback address. If your db is running on the same machine as the code, this address will work
db = await asyncpg.create_pool(**config.DB_CONN_INFO)
db = await postgres.connect()

bot = Bot(description=description, db=db)
if not hasattr(bot, 'uptime'):
Expand Down Expand Up @@ -128,6 +127,7 @@ def __init__(self, **kwargs):
self.process = psutil.Process()
self.ctx = EditingContext

self.rr_image = 'https://moksej.xyz/05zRCwEjkA.png'
self.website = 'https://dreddbot.xyz'
self.support = 'https://discord.gg/f3MaASW'
self.invite = 'https://dreddbot.xyz/invite'
Expand All @@ -142,12 +142,14 @@ def __init__(self, **kwargs):
'dbl': "[Discord Bot list](https://discord.ly/dredd/upvote 'discordbotlist.com')", 'shitgg': "[Top.GG](https://top.gg/bot/667117267405766696/vote 'top.gg')",
'dservices': "[Discord Services](https://discordservices.net/bot/dredd 'discordservices.net')", 'void': "[Void Bots](https://voidbots.net/bot/667117267405766696/vote 'voidbots.net')",
'discords': "[Discords](https://discords.com/bots/bot/667117267405766696/vote 'discords.com')", 'topcord': "[Topcord](https://topcord.xyz/bot/667117267405766696 'topcord.xyz')"}

self.cleverbot = ac.Cleverbot(config.CB_TOKEN)
self.join_counter = Counter() # counter for anti raid so the bot would ban the user if they try to join more than 5 times in short time span
self.counter = Counter() # Counter for global commands cooldown
self.automod_counter = Counter() # Counter for automod logs

self.cache = CacheManager
self.cache_reload = LoadCache
self.cmd_edits = {}
self.dm = {}
self.log_dm = True
Expand Down Expand Up @@ -224,11 +226,14 @@ def __init__(self, **kwargs):
self.reminders = {}
self.mode247 = {}
self.catched_errors = Counter()
self.rr_setup = {}
self.automod_time = {}

# custom stuff
setattr(discord.TextChannel, "can_send", property(self.send_check))
setattr(discord.Thread, "can_send", property(self.send_check))
setattr(discord.Guild, "data", property(self.guild_cache))
setattr(discord.Message, "rr", property(self.message_roles))
setattr(discord.User, "data", property(self.user_cache))
setattr(discord.Member, "data", property(self.user_cache))

Expand All @@ -242,6 +247,9 @@ def guild_cache(self, g) -> DreddGuild:
def user_cache(self, u) -> DreddUser:
return self.cache.get_user(self, u) # type: ignore

def message_roles(self, msg) -> ReactionRoles:
return self.cache.get_message(self, msg.id) # type: ignore

def get(self, k, default=None):
return super().get(k.lower(), default)

Expand Down
51 changes: 40 additions & 11 deletions cogs/automod.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
import discord

from discord.ext import commands
from db.cache import CacheManager as cm, DreddGuild
from db.cache import CacheManager as cm, DreddGuild, Automod as AutomodType, AutomodActions
from utils.checks import moderator, admin, AutomodGlobalStates, AutomodValues
from utils.default import automod_values
from utils.paginator import Pages
from utils.i18n import locale_doc
from utils.components import AutomodTime


# noinspection PyUnresolvedReferences
Expand Down Expand Up @@ -177,10 +178,10 @@ async def automod_set(self, ctx, state: AutomodGlobalStates):
await self.bot.db.execute("UPDATE invites SET level = $1, time = $2 WHERE guild_id = $3", state['invites'], state['time'], ctx.guild.id)
self.bot.invites[ctx.guild.id] = {'level': state['invites'], 'time': state['time']}
if not antimentions:
await self.bot.db.execute("INSERT INTO massmention(guild_id, level, mentions_limit, time) VALUES($1, $2, $3, $4)", ctx.guild.id, state['massmention'], 5, state['time'])
await self.bot.db.execute("INSERT INTO massmention(guild_id, level, mentions_limit, time) VALUES($1, $2, $3, $4)", ctx.guild.id, state['massmention'], 10, state['time'])
else:
await self.bot.db.execute("UPDATE massmention SET level = $1, time = $2 WHERE guild_id = $3", state['massmention'], state['time'], ctx.guild.id)
self.bot.massmention[ctx.guild.id] = {'level': state['massmention'], 'limit': 5, 'time': state['time']}
self.bot.massmention[ctx.guild.id] = {'level': state['massmention'], 'limit': 10, 'time': state['time']}
if not antilinks:
await self.bot.db.execute("INSERT INTO links(guild_id, level, time) VALUES($1, $2, $3)", ctx.guild.id, state['links'], state['time'])
else:
Expand Down Expand Up @@ -218,7 +219,7 @@ async def automod_anti_links(self, ctx, value: AutomodValues):

the_value = value['action']
await ctx.send(_("{0} Successfully set anti links punishment type to **{1}** members.{2}").format(
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), _(" They will be muted/banned for 12 hours by default.") if the_value['action'] in [5, 2] else ''
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), _(" They will be muted/banned for 12 hours by default.") if the_value in [5, 2] else ''
))

@automod.command(name='anti-invites', aliases=['antiinvites', 'invites', 'ai'], brief=_("Toggle anti invites on or off"))
Expand Down Expand Up @@ -251,7 +252,7 @@ async def automod_anti_invites(self, ctx, value: AutomodValues):

the_value = value['action']
await ctx.send(_("{0} Successfully set anti invites punishment type to **{1}** members.{2}").format(
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), _(" They will be muted/banned for 12 hours by default.") if the_value['action'] in [5, 2] else ''
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), _(" They will be muted/banned for 12 hours by default.") if the_value in [5, 2] else ''
))

@automod.command(name='anti-mass-mention', aliases=['antimentions', 'massmentions', 'amm'],
Expand All @@ -260,7 +261,7 @@ async def automod_anti_invites(self, ctx, value: AutomodValues):
@admin(manage_guild=True)
@commands.guild_only()
@locale_doc
async def automod_mass_mention(self, ctx, value: AutomodValues, count: int = 5):
async def automod_mass_mention(self, ctx, value: AutomodValues, count: int = 10):
# sourcery skip: use-assigned-variable
_(""" Toggle anti mass mention on or off and set the mentions limit to whatever number you want """)

Expand All @@ -272,8 +273,8 @@ async def automod_mass_mention(self, ctx, value: AutomodValues, count: int = 5):
# if value['action'] != 0:
# raise commands.MissingRequiredArgument(self.automod_mass_mention.params['count'])

if count and not 1 < count < 16:
raise commands.BadArgument(_("Mentions limit must be between 2 and 15"))
if count and count < 10:
raise commands.BadArgument(_("Mentions limit must be over or equal than 10"))

antimentions = cm.get(self.bot, 'massmention', ctx.guild.id)
if not antimentions and value['action'] != 0:
Expand All @@ -291,7 +292,7 @@ async def automod_mass_mention(self, ctx, value: AutomodValues, count: int = 5):

the_value = value['action'] # type: ignore
await ctx.send(_("{0} Successfully set anti mass mentions punishment type to **{1}** members. Mentions limit - `{2}`.{3}").format(
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), count, _(" They will be muted/banned for 12 hours by default.") if the_value['action'] in [5, 2] else ''
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), count, _(" They will be muted/banned for 12 hours by default.") if the_value in [5, 2] else ''
))

@automod.command(name='anti-mass-caps', aliases=['anticaps', 'masscaps', 'amc'],
Expand Down Expand Up @@ -330,7 +331,7 @@ async def automod_mass_caps(self, ctx, value: AutomodValues, percentage: int = 7

the_value = value['action']
await ctx.send(_("{0} Successfully set anti mass caps punishment type to **{1}** members. Percentage set to - `{2}`.{3}").format(
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), percentage, _(" They will be muted/banned for 12 hours by default.") if the_value['action'] in [5, 2] else ''
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), percentage, _(" They will be muted/banned for 12 hours by default.") if the_value in [5, 2] else ''
))

@automod.command(name='anti-spam', aliases=['antispam', 'spam', 'as'],
Expand Down Expand Up @@ -363,7 +364,7 @@ async def automod_anti_spam(self, ctx, value: AutomodValues):

the_value = value['action']
await ctx.send(_("{0} Successfully set anti spam punishment type to **{1}** members.{2}").format(
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), _(" They will be muted/banned for 12 hours by default.") if the_value['action'] in [5, 2] else ''
self.bot.settings['emojis']['misc']['white-mark'], automod_values(the_value), _(" They will be muted/banned for 12 hours by default.") if the_value in [5, 2] else ''
))

@automod.command(name='ignore-moderators', aliases=['ignoremoderators', 'ignoremods'],
Expand Down Expand Up @@ -410,6 +411,34 @@ async def automod_delete_msgs(self, ctx):
self.bot.automod[ctx.guild.id]['delete_messages'] = True
return await ctx.send(_("{0} I will now be deleting messages from now on.").format(self.bot.settings['emojis']['misc']['white-mark']))

@automod.command(name="temp-time", aliases=["time"], brief=_("Changes the temporary punishment duration."))
@admin(manage_guild=True)
@commands.guild_only()
@commands.cooldown(1, 5, commands.BucketType.member)
@locale_doc
async def automod_temp_time(self, ctx):
_(""" Allows you to change the duration of temporary punishment """)

automod: AutomodType = ctx.guild.data.automod
if not automod:
raise commands.BadArgument(_("Automod is disabled in this server, enable it by using `{0}automod toggle` command").format(ctx.prefix))

options = [
discord.SelectOption(label=_("Anti Spam"), value=1) if automod.spam and automod.spam.level in [int(AutomodActions.temp_mute), int(AutomodActions.temp_ban)] else None, # type: ignore
discord.SelectOption(label=_("Anti Mass Caps"), value=2) if automod.masscaps and automod.masscaps.level in [int(AutomodActions.temp_mute), int(AutomodActions.temp_ban)] else None, # type: ignore
discord.SelectOption(label=_("Anti Invites"), value=3) if automod.invites and automod.invites.level in [int(AutomodActions.temp_mute), int(AutomodActions.temp_ban)] else None, # type: ignore
discord.SelectOption(label=_("Anti Mentions"), value=4) if automod.mentions and automod.mentions.level in [int(AutomodActions.temp_mute), int(AutomodActions.temp_ban)] else None, # type: ignore
discord.SelectOption(label=_("Anti Links"), value=5) if automod.links and automod.links.level in [int(AutomodActions.temp_mute), int(AutomodActions.temp_ban)] else None, # type: ignore
]

if all(value == options[0] for value in options):
return await ctx.send(_("{0} At least one automod value must be set to temp mute or ban.").format(self.bot.settings['emojis']['misc']['warn']))

options = [value for value in options if value is not None]
self.bot.automod_time[(ctx.author.id, ctx.channel.id)] = {"time": None, "options": options}
view = AutomodTime(ctx, options)
return await ctx.send(_("What should the duration of the punishment be?"), view=view)

@commands.group(name='raid-mode', aliases=['raidmode', 'antiraid'], invoke_without_command=True,
brief=_('Manage anti raid mode in the server'))
@admin(manage_guild=True)
Expand Down
2 changes: 1 addition & 1 deletion cogs/boosters.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ async def socialmedia_remove(self, ctx, name: str, social_type: int = None):
elif str(verify_response) == f"{self.bot.settings['emojis']['misc']['red-mark']}":
await ctx.channel.send(_("Alright, I will not be removing your social medias."))
break
except asyncio.TimeoutError:
except asyncio.exceptions.TimeoutError:
await ctx.send(_("{0} You've waited for too long, canceling the command.").format(self.bot.settings['emojis']['misc']['warn']))
break
else:
Expand Down
12 changes: 3 additions & 9 deletions cogs/events/automod.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ def __init__(self, bot):
self.user_cooldowns = commands.CooldownMapping.from_cooldown(10, 12.0, commands.BucketType.user) # checks for member spam
self.invite_cooldown = commands.CooldownMapping.from_cooldown(5, 60.0, commands.BucketType.member) # checks for invites
self.link_cooldown = commands.CooldownMapping.from_cooldown(5, 60.0, commands.BucketType.member)
self.caps_content = commands.CooldownMapping.from_cooldown(6, 10.0, commands.BucketType.member) # checks for cpas
self.mentions_limit = commands.CooldownMapping.from_cooldown(5, 17.0, commands.BucketType.member)
self.caps_content = commands.CooldownMapping.from_cooldown(6, 10.0, commands.BucketType.member) # checks for caps

self.new_users = commands.CooldownMapping.from_cooldown(30, 35.0, commands.BucketType.channel)

Expand Down Expand Up @@ -298,7 +297,6 @@ async def anti_links(self, message):
await self.execute_punishment(antilinks['level'], message, reason, btime.FutureTime(antilinks['time']))

async def anti_mentions(self, message):
current = message.created_at.timestamp()
reason = _('Spamming mentions')
automod = cm.get(self.bot, 'automod', message.guild.id)
massmention = cm.get(self.bot, 'massmention', message.guild.id)
Expand All @@ -308,15 +306,11 @@ async def anti_mentions(self, message):

limit = massmention['limit']
mentions = sum(not x.bot and x.id != message.author.id for x in message.mentions)
if mentions > limit:
content_bucket = self.mentions_limit.get_bucket(message)
retry = content_bucket.update_rate_limit(current)
if mentions >= limit:
if automod['delete_messages'] and message.channel.permissions_for(message.guild.me).manage_messages:
await message.delete()

if retry:
content_bucket.reset()
await self.execute_punishment(massmention['level'], message, reason, btime.FutureTime(massmention['time']))
await self.execute_punishment(massmention['level'], message, reason, btime.FutureTime(massmention['time']))

async def anti_raid(self, member):
raidmode = cm.get(self.bot, 'raidmode', member.guild.id)
Expand Down
31 changes: 24 additions & 7 deletions cogs/events/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from time import time
from db.cache import CacheManager as CM
from utils import btime, checks, default, logger as logging
from utils import btime, checks, default, logger as logging, components
from datetime import datetime, timedelta, timezone
from contextlib import suppress

Expand All @@ -37,6 +37,8 @@ def __init__(self, bot):
self.bot = bot
self.help_icon = ''

self.persistent_views_added = False

self.cooldown_bot_mentions = commands.CooldownMapping.from_cooldown(1, 10.0, commands.BucketType.channel)
self.cooldown_afk_mentions = commands.CooldownMapping.from_cooldown(5, 10.0, commands.BucketType.channel)

Expand All @@ -50,8 +52,8 @@ async def bot_check(self, ctx):
if ctx.bot.user.id == 663122720044875796 and ctx.guild.data.beta: # type: ignore
return True

# if ctx.bot.user.id == 663122720044875796 and not await ctx.bot.is_owner(ctx.author) or not ctx.guild.data.beta: # type: ignore
# return False
if ctx.bot.user.id == 663122720044875796 and not await ctx.bot.is_owner(ctx.author): # type: ignore
return False

blacklist = await ctx.bot.is_blacklisted(ctx.author)
if blacklist and blacklist['type'] == 2:
Expand Down Expand Up @@ -81,14 +83,16 @@ async def on_ready(self):
await self.bot.change_presence(status='online', activity=discord.Activity(type=discord.ActivityType.playing, name="-help or @Dredd help"))
dredd_logger.info(f"[BOT] Booted up, boot time - {boot_time}")

if not self.persistent_views_added:
view, _ = components.create_self_roles()
self.bot.add_view(view)
dredd_logger.info("[BOT] Successfully added reaction roles view.")
self.persistent_views_added = True

support_guild = self.bot.get_guild(self.bot.settings['servers']['main'])
await support_guild.chunk(cache=True)
print(f"{support_guild} chunked")

# for guild in self.bot.guilds:
# if guild.id not in self.bot.prefix:
# self.bot.dispatch('guild_join', guild)

@commands.Cog.listener()
async def on_message(self, message): # sourcery no-metrics
if message.author.bot:
Expand Down Expand Up @@ -361,6 +365,9 @@ async def on_guild_remove(self, guild): # sourcery no-metrics
# get dispatched before on_guild_join. (if server kicks new members immediately)
# That was basically updating the data in the db and then immediately
# deleting it. Ex here: https://cdn.dreddbot.xyz/tI0o2y
if guild.name is None:
return

await asyncio.sleep(3)

check = CM.get(self.bot, 'blacklist', guild.id)
Expand Down Expand Up @@ -530,6 +537,16 @@ async def snipes_logging(self, message):

self.bot.snipes[message.channel.id] = {'message': message.content, 'deleted_at': discord.utils.utcnow(), 'author': message.author.id, 'nsfw': message.channel.is_nsfw()}

@commands.Cog.listener('on_raw_message_delete')
async def reaction_roles_delete(self, payload):
if self.bot.cache.get_message(self.bot, payload.message_id):
await self.bot.db.execute("DELETE FROM reactionroles WHERE message_id = $1", payload.message_id)
self.bot.rr.pop(payload.message_id, None)

@commands.Cog.listener('on_guild_channel_delete')
async def reaction_roles_channel_delete(self, channel):
await self.bot.db.execute("DELETE FROM reactionroles WHERE channel_id = $1", channel.id)


def setup(bot):
bot.add_cog(Events(bot))
Loading

0 comments on commit 9f955a8

Please sign in to comment.