Skip to content

Commit

Permalink
Merge pull request #160 from Tortoise-Community/dev
Browse files Browse the repository at this point in the history
Merge dev branch
  • Loading branch information
Ryuga authored Oct 15, 2021
2 parents 47bd32d + 556b825 commit 7524c7a
Show file tree
Hide file tree
Showing 7 changed files with 328 additions and 318 deletions.
445 changes: 263 additions & 182 deletions Pipfile.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
class Bot(commands.Bot):
# If not empty then only these will be loaded. Good for local debugging. If empty all found are loaded.
allowed_extensions = ()
banned_extensions = ("advent_of_code", "invite_tracker")
banned_extensions = ("advent_of_code",)

def __init__(self, prefix="t.", *args, **kwargs):
super(Bot, self).__init__(*args, command_prefix=prefix, intents=discord.Intents.all(), **kwargs)
Expand Down
14 changes: 5 additions & 9 deletions bot/cogs/defcon.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(self, bot):
self.bot = bot
self.defcon_active = False
self._kicked_while_defcon_was_active: int = 0
self.joins_per_min_trigger = 10
self.joins_per_min_trigger = 7
self._joins: Set[Tuple[datetime, int]] = set()
self.staff_channel = bot.get_channel(constants.staff_channel_id)

Expand All @@ -40,14 +40,10 @@ async def on_member_join(self, member: discord.Member):
@tasks.loop(minutes=1)
async def mass_join_check(self):
current_time = datetime.now()
expired_joins = set()

for join in self._joins:
for join in self._joins.copy():
if (current_time - join[0]).seconds >= 60:
expired_joins.add(join)

for expired_join in expired_joins:
self._joins.remove(expired_join)
self._joins.remove(join)

if len(self._joins) >= self.joins_per_min_trigger:
if self.defcon_active:
Expand Down Expand Up @@ -76,8 +72,8 @@ async def disable_defcon(self, ctx):
@commands.has_guild_permissions(administrator=True)
@commands.check(check_if_it_is_tortoise_guild)
async def set_defcon_trigger(self, ctx, trigger: int):
if not 10 <= trigger <= 100:
return await ctx.send(embed=failure("Please use integer from 10 to 100."))
if not 7 <= trigger <= 100:
return await ctx.send(embed=failure("Please use integer from 7 to 100."))

self.joins_per_min_trigger = trigger
await ctx.send(embed=success(f"Successfully changed DEFCON trigger to {trigger} users/min."))
Expand Down
44 changes: 22 additions & 22 deletions bot/cogs/invite_tracker.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
from discord import Invite, Member
from discord.ext import commands

from bot.utils import invite_help
from bot.utils import invite_help, embed_handler
from bot.constants import tortoise_guild_id, successful_verifications_channel_id


class InviteTracker(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.tracker = invite_help.TRACKER(bot)
self.tracker = invite_help.GuildInviteTracker(self.bot.get_guild(tortoise_guild_id))
self.log_channel = self.bot.get_channel(successful_verifications_channel_id)
self.bot.loop.create_task(self.tracker.refresh_invite_cache())

@commands.Cog.listener()
async def on_ready(self):
await self.tracker.all_invites()
async def on_invite_create(self, invite: Invite):
await self.tracker.add_new_invite(invite)

@commands.Cog.listener()
async def on_invite_create(self, invite):
await self.tracker.update_invite(invite)
async def on_invite_delete(self, invite: Invite):
await self.tracker.remove_invite(invite)

@commands.Cog.listener()
async def on_guild_join(self, guild):
await self.tracker.create_guild_invites(guild)

@commands.Cog.listener()
async def on_invite_delete(self, invite):
await self.tracker.delete_guild_invites(invite)

@commands.Cog.listener()
async def on_guild_remove(self, guild):
await self.tracker.remove_invites(guild)

@commands.Cog.listener()
async def on_member_join(self, member):
# TODO
# inviter = await self.tracker.get_inviter(member).id
pass
async def on_member_join(self, member: Member):
inviter = await self.tracker.track_invite()
if inviter:
await self.log_channel.send(embed=embed_handler.info(
f"New member {member} was invited by {inviter}",
member=member,
title=""
))


def setup(bot):
bot.add_cog(InviteTracker(bot))
11 changes: 6 additions & 5 deletions bot/cogs/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async def security_check(self, message: Message):
Some checks can delete the message, so no need to run additional checks if message got deleted.
:param message: message to run checks on
"""
if self.skip_security(message):
if self.is_security_whitelisted(message):
return

is_message_deleted = False
Expand All @@ -50,7 +50,7 @@ async def security_check(self, message: Message):
if not is_message_deleted:
await self.deal_with_long_code(message)

def skip_security(self, message: Message) -> bool:
def is_security_whitelisted(self, message: Message) -> bool:
"""
In which cases we will skip our security check for message.
:param message: message on which we will potentially run security checks
Expand Down Expand Up @@ -110,9 +110,10 @@ async def deal_with_vulgar_words(self, message: Message) -> None:
:param message: message to check for vulgar words
:return: bool, was the passed message deleted or not?
"""
message_content = message.content.lower()
for category, banned_words in self.banned_words.loaded.items():
for banned_word in banned_words:
if banned_word in message.content.lower():
if banned_word in message_content:
embed = info(
f"Curse word **{banned_word}** detected from the category **{category}**",
message.guild.me,
Expand Down Expand Up @@ -215,7 +216,7 @@ async def on_message(self, message):
async def on_message_edit(self, msg_before, msg_after):
if msg_before.content == msg_after.content:
return
elif self.skip_security(msg_after):
elif self.is_security_whitelisted(msg_after):
return

# Log that the message was edited for security reasons
Expand All @@ -236,7 +237,7 @@ async def on_message_edit(self, msg_before, msg_after):
async def on_message_delete(self, message):
if message.content == "":
return # if it had only attachment for example
elif self.skip_security(message):
elif self.is_security_whitelisted(message):
return

msg = (
Expand Down
23 changes: 5 additions & 18 deletions bot/cogs/tortoise_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,22 +190,8 @@ async def _new_member_register_in_database(self, member: discord.Member):
)
await member.send(embed=footer_embed(dm_msg, "Welcome"))

async def _new_member_direct_access(self, member: discord.Member):
logger.info(f"Member {member} joined directly from website, giving access to guild.")
await self.add_verified_roles_to_member(member)
await self.bot.api_client.member_rejoined(member)
await self.log_channel.send(embed=welcome(f"{member} has joined to Tortoise Community."))
msg = (
"Welcome to Tortoise Community!\n\n"
"We see you've come directly from our website after verification,\n"
"you've been given access to our server, enjoy your stay."
)
await member.send(embed=footer_embed(msg, "Welcome"))

async def _new_member_re_joined(self, member: discord.Member, verified: bool):
if verified:
# this factor will be removed in the next update
logger.info(f"Member {member} re-joined and is verified in database, adding previous roles..")
async def _member_re_joined(self, member: discord.Member):
logger.info(f"Member {member} re-joined and is verified in database, adding previous roles..")
previous_roles = await self.bot.api_client.get_member_roles(member.id)
await self.add_verified_roles_to_member(member, previous_roles)
await self.bot.api_client.member_rejoined(member)
Expand All @@ -224,16 +210,17 @@ async def on_member_update(self, before, after):
"""
if before.pending is True and after.pending is False:

logger.info(f"New member joined {after}")
logger.info(f"New member verified from discord {after}")
try:
member_meta = await self.bot.api_client.get_member_meta(after.id)
except ResponseCodeError:
await self._new_member_register_in_database(after)
else:
if member_meta["leave_date"] is None and member_meta["verified"]:
# Could be put to use for new website
pass
else:
await self._new_member_re_joined(after, member_meta["verified"])
await self._member_re_joined(after)

if before.roles == after.roles or self._database_role_update_lock:
return
Expand Down
107 changes: 26 additions & 81 deletions bot/utils/invite_help.py
Original file line number Diff line number Diff line change
@@ -1,93 +1,38 @@
import sys

import discord


class CACHE:
def __init__(self):
self.cache = {}
self.size = 40

def __iter__(self):
return self.cache
class GuildInviteTracker:
def __init__(self, guild):
self.guild = guild
self._cache = {}

async def refresh_invite_cache(self):
self._cache = await self.get_all_invites()

class TRACKER:
def __init__(self, bot):
self.bot = bot
self.__cache = CACHE()
async def get_inviter(self, code):
return self._cache.get(code)["created_by"]

async def all_invites(self):
for guild in self.bot.guilds:
self.__cache.cache[guild.id] = {}
try:
invites = await guild.invites()
for invite in invites:
if invite.inviter not in self.__cache.cache[guild.id].keys():
self.__cache.cache[guild.id][invite.inviter] = []
self.__cache.cache[guild.id][invite.inviter].append(invite)
self.__cache.size = sys.getsizeof(self.__cache.cache)
except discord.errors.Forbidden:
pass

async def update_invite(self, invite):
try:
if invite.guild.id not in self.__cache.cache.keys():
self.__cache.cache[invite.guild.id] = {}
if invite.inviter not in self.__cache.cache[invite.guild.id].keys():
self.__cache.cache[invite.guild.id][invite.inviter] = []
self.__cache.cache[invite.guild.id][invite.inviter].append(invite)
self.__cache.size = sys.getsizeof(self.__cache.cache)
except discord.errors.Forbidden:
return
async def add_new_invite(self, invite):
if invite.code not in self._cache.keys():
self._cache[invite.code] = {"created_by": invite.inviter, "uses": invite.uses}

async def remove_invites(self, invite):
for key in self.__cache.cache:
for lists in self.__cache.cache[key]:
user = self.__cache.cache[key][lists]
if invite in user:
self.__cache.cache[key][lists].remove(invite)
self.__cache.size = sys.getsizeof(self.__cache.cache)
break
async def remove_invite(self, invite):
self._cache.pop(invite.code, None)

async def delete_guild_invites(self, guild: discord.Guild):
if guild.id in self.__cache.cache.keys():
self.__cache.size = sys.getsizeof(self.__cache.cache)
del self.__cache.cache[guild.id]
async def track_invite(self):
new_invites = await self.get_all_invites()
for code, data in new_invites.items():
if data["uses"] > self._cache.get(code)["uses"]:
self._cache = new_invites
return await self.get_inviter(code)

async def create_guild_invites(self, guild: discord.Guild):
async def get_all_invites(self) -> dict:
try:
invites = await guild.invites()
self.__cache.cache[guild.id] = {}
invites = await self.guild.invites()
new_invites = {}
for invite in invites:
if invite.inviter not in self.__cache.cache[guild.id].keys():
self.__cache.cache[guild.id][invite.inviter] = []
self.__cache.cache[guild.id][invite.inviter].append(invite)
self.__cache.size = sys.getsizeof(self.__cache.cache)
except discord.errors.Forbidden:
return

async def get_inviter(self, member: discord.Member):
invites = {}
try:
new_invites = await member.guild.invites()
if invite.code not in new_invites.keys():
new_invites[invite.code] = {"created_by": invite.inviter, "uses": invite.uses}
return new_invites
except discord.errors.Forbidden:
return
for invite in new_invites:
if invite.inviter not in invites.keys():
invites[invite.inviter] = []
invites[invite.inviter].append(invite)
for new_invite_key in invites:
for cached_invite_key in self.__cache.cache[member.guild.id]:
if new_invite_key == cached_invite_key:
new_invite_list = invites[new_invite_key]
cached_invite_list = self.__cache.cache[member.guild.id][cached_invite_key]
for new_invite in new_invite_list:
for old_invite in cached_invite_list:
if new_invite.code == old_invite.code and new_invite.uses-old_invite.uses >= 1:
cached_invite_list.remove(old_invite)
cached_invite_list.append(new_invite)
self.__cache.size = sys.getsizeof(self.__cache.cache)
return new_invite_key
else:
return None
pass

0 comments on commit 7524c7a

Please sign in to comment.