Break out background tasks and events into seperate modules

This commit is contained in:
Zeva Rose 2021-07-25 16:46:23 -06:00
parent d108c910c2
commit bdc2eb6a78
9 changed files with 389 additions and 327 deletions

View file

@ -1,30 +1,15 @@
import asyncio import asyncio
import re
from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
import pymongo from discord import Intents
from discord import DMChannel, Intents, Member, Message
from discord.ext import commands from discord.ext import commands
from discord.ext.tasks import loop
from discord.utils import find from discord.utils import find
from discord_slash import SlashCommand from discord_slash import SlashCommand
from psutil import Process from psutil import Process
from jarvis import logo, utils from jarvis import logo, tasks, utils
from jarvis.config import get_config from jarvis.config import get_config
from jarvis.db import DBManager from jarvis.db import DBManager
from jarvis.db.types import (
Autopurge,
Autoreact,
Ban,
Lock,
Mute,
Setting,
Warning,
)
from jarvis.utils import build_embed
from jarvis.utils.field import Field
if asyncio.get_event_loop().is_closed(): if asyncio.get_event_loop().is_closed():
asyncio.set_event_loop(asyncio.new_event_loop()) asyncio.set_event_loop(asyncio.new_event_loop())
@ -33,11 +18,6 @@ intents = Intents.default()
intents.members = True intents.members = True
restart_ctx = None restart_ctx = None
invites = re.compile(
r"(?:https?://)?(?:www.)?(?:discord.(?:gg|io|me|li)|discord(?:app)?.com/invite)/([^\s/]+?)(?=\b)",
flags=re.IGNORECASE,
)
jarvis = commands.Bot( jarvis = commands.Bot(
command_prefix=utils.get_prefix, intents=intents, help_command=None command_prefix=utils.get_prefix, intents=intents, help_command=None
@ -50,6 +30,8 @@ __version__ = "1.6.0"
db = DBManager(get_config().mongo).mongo db = DBManager(get_config().mongo).mongo
jarvis_db = db.jarvis jarvis_db = db.jarvis
logo = logo.get_logo(get_config().logo)
@jarvis.event @jarvis.event
async def on_ready(): async def on_ready():
@ -74,307 +56,6 @@ async def on_ready():
restart_ctx = None restart_ctx = None
@jarvis.event
async def on_member_join(user: Member):
guild = user.guild
mutes = Mute.get_active(guild=guild.id)
if mutes and len(mutes) >= 1:
mute_role = Setting.get(guild=guild.id, setting="mute")
role = guild.get_role(mute_role.value)
await user.add_roles(
role, reason="User is muted still muted from prior mute"
)
unverified = Setting.get(guild=guild.id, setting="unverified")
if unverified:
role = guild.get_role(unverified.value)
await user.add_roles(role, reason="User just joined and is unverified")
@jarvis.event
async def on_message(message: Message):
channel = find(
lambda x: x.id == 599068193339736096, message.channel_mentions
)
if channel and message.author.id == 293795462752894976:
await channel.send(
content="https://cdn.discordapp.com/attachments/"
+ "664621130044407838/805218508866453554/tech.gif"
)
if (
not isinstance(message.channel, DMChannel)
and message.author.id != jarvis.user.id
):
autoreact = Autoreact.get(
guild=message.guild.id,
channel=message.channel.id,
)
if autoreact:
for reaction in autoreact.reactions:
await message.add_reaction(reaction)
massmention = Setting.get(
guild=message.guild.id,
setting="massmention",
)
if (
massmention.value > 0
and len(message.mentions)
- (1 if message.author in message.mentions else 0)
> massmention.value
):
warning = Warning(
active=True,
admin=get_config().client_id,
duration=24,
guild=message.guild.id,
reason="Mass Mention",
user=message.author.id,
)
warning.insert()
fields = [Field("Reason", "Mass Mention", False)]
embed = build_embed(
title="Warning",
description=f"{message.author.mention} has been warned",
fields=fields,
)
embed.set_author(
name=message.author.nick
if message.author.nick
else message.author.name,
icon_url=message.author.avatar_url,
)
embed.set_footer(
text=f"{message.author.name}#{message.author.discriminator} "
+ f"| {message.author.id}"
)
await message.channel.send(embed=embed)
roleping = Setting.get(guild=message.guild.id, setting="roleping")
roles = []
for mention in message.role_mentions:
roles.append(mention.id)
for mention in message.mentions:
for role in mention.roles:
roles.append(role.id)
if (
roleping
and any(x in roleping.value for x in roles)
and not any(x.id in roleping.value for x in message.author.roles)
):
warning = Warning(
active=True,
admin=get_config().client_id,
duration=24,
guild=message.guild.id,
reason="Pinged a blocked role/user with a blocked role",
user=message.author.id,
)
warning.insert()
fields = [
Field(
"Reason",
"Pinged a blocked role/user with a blocked role",
False,
)
]
embed = build_embed(
title="Warning",
description=f"{message.author.mention} has been warned",
fields=fields,
)
embed.set_author(
name=message.author.nick
if message.author.nick
else message.author.name,
icon_url=message.author.avatar_url,
)
embed.set_footer(
text=f"{message.author.name}#{message.author.discriminator} "
+ f"| {message.author.id}"
)
await message.channel.send(embed=embed)
autopurge = Autopurge.get(
guild=message.guild.id, channel=message.channel.id
)
if autopurge:
await message.delete(delay=autopurge.delay)
content = re.sub(r"\s+", "", message.content)
match = invites.search(content)
if match:
guild_invites = await message.guild.invites()
allowed = [x.code for x in guild_invites] + [
"dbrand",
"VtgZntXcnZ",
]
if match.group(1) not in allowed:
await message.delete()
warning = Warning(
active=True,
admin=get_config().client_id,
duration=24,
guild=message.guild.id,
reason="Sent an invite link",
user=message.author.id,
)
warning.insert()
fields = [
Field(
"Reason",
"Sent an invite link",
False,
)
]
embed = build_embed(
title="Warning",
description=f"{message.author.mention} has been warned",
fields=fields,
)
embed.set_author(
name=message.author.nick
if message.author.nick
else message.author.name,
icon_url=message.author.avatar_url,
)
embed.set_footer(
text=f"{message.author.name}#"
+ f"{message.author.discriminator} "
+ f"| {message.author.id}"
)
await message.channel.send(embed=embed)
await jarvis.process_commands(message)
@jarvis.event
async def on_guild_join(guild):
general = find(lambda x: x.name == "general", guild.channels)
if general and general.permissions_for(guild.me).send_messages:
await general.send(
"Allow me to introduce myself. I am J.A.R.V.I.S., a virtual "
+ "artificial intelligence, and I'm here to assist you with a "
+ "variety of tasks as best I can, "
+ "24 hours a day, seven days a week."
)
await asyncio.sleep(1)
await general.send("Importing all preferences from home interface...")
# Set some default settings
setting = Setting(guild=guild.id, setting="massmention", value=5)
setting.insert()
await general.send("Systems are now fully operational")
@loop(minutes=1)
async def unmute():
mutes = Mute.get_active(duration={"$gt": 0})
mute_roles = Setting.get_many(setting="mute")
updates = []
for mute in mutes:
if (
mute.created_at + timedelta(minutes=mute.duration)
< datetime.utcnow()
):
mute_role = [x.value for x in mute_roles if x.guild == mute.guild][
0
]
guild = await jarvis.fetch_guild(mute.guild)
role = guild.get_role(mute_role)
user = await guild.fetch_member(mute.user)
if user:
if role in user.roles:
await user.remove_roles(role, reason="Mute expired")
# Objects can't handle bulk_write, so handle it via raw methods
updates.append(
pymongo.UpdateOne(
{
"user": user.id,
"guild": guild.id,
"created_at": mute.created_at,
},
{"$set": {"active": False}},
)
)
if updates:
jarvis_db.mutes.bulk_write(updates)
@loop(minutes=10)
async def unban():
bans = Ban.get_active(type="temp")
updates = []
for ban in bans:
if ban.created_at + timedelta(
hours=ban.duration
) < datetime.utcnow() + timedelta(minutes=10):
guild = await jarvis.fetch_guild(ban.guild)
user = await jarvis.fetch_user(ban.user)
if user:
guild.unban(user)
updates.append(
pymongo.UpdateOne(
{
"user": user.id,
"guild": guild.id,
"created_at": ban.created_at,
"type": "temp",
},
{"$set": {"active": False}},
)
)
if updates:
jarvis_db.bans.bulk_write(updates)
@loop(minutes=1)
async def unlock():
locks = Lock.get_active()
updates = []
for lock in locks:
if (
lock.created_at + timedelta(minutes=lock.duration)
< datetime.utcnow()
):
guild = await jarvis.fetch_guild(lock.guild)
channel = await jarvis.fetch_channel(lock.channel)
if channel:
roles = await guild.fetch_roles()
for role in roles:
overrides = channel.overwrites_for(role)
overrides.send_messages = None
await channel.set_permissions(
role, overwrite=overrides, reason="Lock expired"
)
updates.append(
pymongo.UpdateOne(
{
"channel": channel.id,
"guild": guild.id,
"created_at": lock.created_at,
},
{"$set": {"active": False}},
)
)
if updates:
jarvis_db.locks.bulk_write(updates)
@loop(hours=1)
async def unwarn():
warns = Warning.get_active()
updates = []
for warn in warns:
if (
warn.created_at + timedelta(hours=warn.duration)
< datetime.utcnow()
):
updates.append(
pymongo.UpdateOne(
{"_id": warn._id}, {"$set": {"active": False}}
)
)
if updates:
jarvis_db.warns.bulk_write(updates)
def run(ctx=None): def run(ctx=None):
global restart_ctx global restart_ctx
if ctx: if ctx:
@ -388,11 +69,9 @@ def run(ctx=None):
config.client_id config.client_id
) )
) )
unmute.start()
unban.start()
unlock.start()
unwarn.start()
jarvis.max_messages = config.max_messages jarvis.max_messages = config.max_messages
tasks.init()
jarvis.run(config.token, bot=True, reconnect=True) jarvis.run(config.token, bot=True, reconnect=True)
for cog in jarvis.cogs: for cog in jarvis.cogs:
session = getattr(cog, "_session", None) session = getattr(cog, "_session", None)

26
jarvis/events/guild.py Normal file
View file

@ -0,0 +1,26 @@
import asyncio
from discord.utils import find
from jarvis import jarvis
from jarvis.db.types import Setting
@jarvis.event
async def on_guild_join(guild):
general = find(lambda x: x.name == "general", guild.channels)
if general and general.permissions_for(guild.me).send_messages:
await general.send(
"Allow me to introduce myself. I am J.A.R.V.I.S., a virtual "
+ "artificial intelligence, and I'm here to assist you with a "
+ "variety of tasks as best I can, "
+ "24 hours a day, seven days a week."
)
await asyncio.sleep(1)
await general.send("Importing all preferences from home interface...")
# Set some default settings
setting = Setting(guild=guild.id, setting="massmention", value=5)
setting.insert()
await general.send("Systems are now fully operational")

20
jarvis/events/member.py Normal file
View file

@ -0,0 +1,20 @@
from discord import Member
from jarvis import jarvis
from jarvis.db.types import Mute, Setting
@jarvis.event
async def on_member_join(user: Member):
guild = user.guild
mutes = Mute.get_active(guild=guild.id)
if mutes and len(mutes) >= 1:
mute_role = Setting.get(guild=guild.id, setting="mute")
role = guild.get_role(mute_role.value)
await user.add_roles(
role, reason="User is muted still muted from prior mute"
)
unverified = Setting.get(guild=guild.id, setting="unverified")
if unverified:
role = guild.get_role(unverified.value)
await user.add_roles(role, reason="User just joined and is unverified")

188
jarvis/events/message.py Normal file
View file

@ -0,0 +1,188 @@
import re
from discord import DMChannel, Message
from discord.utils import find
from jarvis import jarvis
from jarvis.config import get_config
from jarvis.db.types import Autopurge, Autoreact, Setting
from jarvis.utils import build_embed
from jarvis.utils.field import Field
invites = re.compile(
r"(?:https?://)?(?:www.)?(?:discord.(?:gg|io|me|li)|discord(?:app)?.com/invite)/([^\s/]+?)(?=\b)",
flags=re.IGNORECASE,
)
async def autopurge(message):
autopurge = Autopurge.get(
guild=message.guild.id, channel=message.channel.id
)
if autopurge:
await message.delete(delay=autopurge.delay)
async def autoreact(message):
autoreact = Autoreact.get(
guild=message.guild.id,
channel=message.channel.id,
)
if autoreact:
for reaction in autoreact.reactions:
await message.add_reaction(reaction)
async def checks(message):
# #tech
channel = find(
lambda x: x.id == 599068193339736096, message.channel_mentions
)
if channel and message.author.id == 293795462752894976:
await channel.send(
content="https://cdn.discordapp.com/attachments/"
+ "664621130044407838/805218508866453554/tech.gif"
)
content = re.sub(r"\s+", "", message.content)
match = invites.search(content)
if match:
guild_invites = await message.guild.invites()
allowed = [x.code for x in guild_invites] + [
"dbrand",
"VtgZntXcnZ",
]
if match.group(1) not in allowed:
await message.delete()
warning = Warning(
active=True,
admin=get_config().client_id,
duration=24,
guild=message.guild.id,
reason="Sent an invite link",
user=message.author.id,
)
warning.insert()
fields = [
Field(
"Reason",
"Sent an invite link",
False,
)
]
embed = build_embed(
title="Warning",
description=f"{message.author.mention} has been warned",
fields=fields,
)
embed.set_author(
name=message.author.nick
if message.author.nick
else message.author.name,
icon_url=message.author.avatar_url,
)
embed.set_footer(
text=f"{message.author.name}#"
+ f"{message.author.discriminator} "
+ f"| {message.author.id}"
)
await message.channel.send(embed=embed)
async def massmention(message):
massmention = Setting.get(
guild=message.guild.id,
setting="massmention",
)
if (
massmention.value > 0
and len(message.mentions)
- (1 if message.author in message.mentions else 0)
> massmention.value
):
warning = Warning(
active=True,
admin=get_config().client_id,
duration=24,
guild=message.guild.id,
reason="Mass Mention",
user=message.author.id,
)
warning.insert()
fields = [Field("Reason", "Mass Mention", False)]
embed = build_embed(
title="Warning",
description=f"{message.author.mention} has been warned",
fields=fields,
)
embed.set_author(
name=message.author.nick
if message.author.nick
else message.author.name,
icon_url=message.author.avatar_url,
)
embed.set_footer(
text=f"{message.author.name}#{message.author.discriminator} "
+ f"| {message.author.id}"
)
await message.channel.send(embed=embed)
async def roleping(message):
roleping = Setting.get(guild=message.guild.id, setting="roleping")
roles = []
for mention in message.role_mentions:
roles.append(mention.id)
for mention in message.mentions:
for role in mention.roles:
roles.append(role.id)
if (
roleping
and any(x in roleping.value for x in roles)
and not any(x.id in roleping.value for x in message.author.roles)
):
warning = Warning(
active=True,
admin=get_config().client_id,
duration=24,
guild=message.guild.id,
reason="Pinged a blocked role/user with a blocked role",
user=message.author.id,
)
warning.insert()
fields = [
Field(
"Reason",
"Pinged a blocked role/user with a blocked role",
False,
)
]
embed = build_embed(
title="Warning",
description=f"{message.author.mention} has been warned",
fields=fields,
)
embed.set_author(
name=message.author.nick
if message.author.nick
else message.author.name,
icon_url=message.author.avatar_url,
)
embed.set_footer(
text=f"{message.author.name}#{message.author.discriminator} "
+ f"| {message.author.id}"
)
await message.channel.send(embed=embed)
@jarvis.event
async def on_message(message: Message):
if (
not isinstance(message.channel, DMChannel)
and message.author.id != jarvis.user.id
):
await autoreact(message)
await massmention(message)
await roleping(message)
await autopurge(message)
await checks(message)
await jarvis.process_commands(message)

8
jarvis/tasks/__init__.py Normal file
View file

@ -0,0 +1,8 @@
from jarvis.tasks import unban, unlock, unmute, unwarn
def init():
unban.unban.start()
unlock.unlock.start()
unmute.unmute.start()
unwarn.unwarn.start()

34
jarvis/tasks/unban.py Normal file
View file

@ -0,0 +1,34 @@
from datetime import datetime, timedelta
import pymongo
from discord.ext.tasks import loop
from jarvis import jarvis, jarvis_db
from jarvis.db.types import Ban
@loop(minutes=10)
async def unban():
bans = Ban.get_active(type="temp")
updates = []
for ban in bans:
if ban.created_at + timedelta(
hours=ban.duration
) < datetime.utcnow() + timedelta(minutes=10):
guild = await jarvis.fetch_guild(ban.guild)
user = await jarvis.fetch_user(ban.user)
if user:
guild.unban(user)
updates.append(
pymongo.UpdateOne(
{
"user": user.id,
"guild": guild.id,
"created_at": ban.created_at,
"type": "temp",
},
{"$set": {"active": False}},
)
)
if updates:
jarvis_db.bans.bulk_write(updates)

40
jarvis/tasks/unlock.py Normal file
View file

@ -0,0 +1,40 @@
from datetime import datetime, timedelta
import pymongo
from discord.ext.tasks import loop
from jarvis import jarvis, jarvis_db
from jarvis.db.types import Lock
@loop(minutes=1)
async def unlock():
locks = Lock.get_active()
updates = []
for lock in locks:
if (
lock.created_at + timedelta(minutes=lock.duration)
< datetime.utcnow()
):
guild = await jarvis.fetch_guild(lock.guild)
channel = await jarvis.fetch_channel(lock.channel)
if channel:
roles = await guild.fetch_roles()
for role in roles:
overrides = channel.overwrites_for(role)
overrides.send_messages = None
await channel.set_permissions(
role, overwrite=overrides, reason="Lock expired"
)
updates.append(
pymongo.UpdateOne(
{
"channel": channel.id,
"guild": guild.id,
"created_at": lock.created_at,
},
{"$set": {"active": False}},
)
)
if updates:
jarvis_db.locks.bulk_write(updates)

42
jarvis/tasks/unmute.py Normal file
View file

@ -0,0 +1,42 @@
from datetime import datetime, timedelta
import pymongo
from discord.ext.tasks import loop
from jarvis import jarvis, jarvis_db
from jarvis.db.types import Mute, Setting
@loop(minutes=1)
async def unmute():
mutes = Mute.get_active(duration={"$gt": 0})
mute_roles = Setting.get_many(setting="mute")
updates = []
for mute in mutes:
if (
mute.created_at + timedelta(minutes=mute.duration)
< datetime.utcnow()
):
mute_role = [x.value for x in mute_roles if x.guild == mute.guild][
0
]
guild = await jarvis.fetch_guild(mute.guild)
role = guild.get_role(mute_role)
user = await guild.fetch_member(mute.user)
if user:
if role in user.roles:
await user.remove_roles(role, reason="Mute expired")
# Objects can't handle bulk_write, so handle it via raw methods
updates.append(
pymongo.UpdateOne(
{
"user": user.id,
"guild": guild.id,
"created_at": mute.created_at,
},
{"$set": {"active": False}},
)
)
if updates:
jarvis_db.mutes.bulk_write(updates)

25
jarvis/tasks/unwarn.py Normal file
View file

@ -0,0 +1,25 @@
from datetime import datetime, timedelta
import pymongo
from discord.ext.tasks import loop
from jarvis import jarvis_db
from jarvis.db.types import Warning
@loop(hours=1)
async def unwarn():
warns = Warning.get_active()
updates = []
for warn in warns:
if (
warn.created_at + timedelta(hours=warn.duration)
< datetime.utcnow()
):
updates.append(
pymongo.UpdateOne(
{"_id": warn._id}, {"$set": {"active": False}}
)
)
if updates:
jarvis_db.warns.bulk_write(updates)