-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9f39f7e
commit abb9be1
Showing
32 changed files
with
1,185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
website/scripts/jquery.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import logging | ||
import asyncio | ||
from hata.ext.commands import setup_ext_commands | ||
from importlib import import_module | ||
from bot.client import Client | ||
from bot.logger import Logger | ||
from website.server import Server | ||
from bot import constants | ||
from database.database import Database | ||
|
||
client = Client(constants.Auth.BOT_TOKEN) | ||
setup_ext_commands(client, client._get_prefix) | ||
client.server = Server(client=client) | ||
client.database = Database(client=client) | ||
client.logger = Logger(client=client) | ||
|
||
logging.basicConfig(level=logging.DEBUG) | ||
|
||
client.load_extension(import_module('.extensions.main', package='bot').Main()) | ||
client.load_extension(import_module('.extensions.fun', package='bot').Fun()) | ||
client.load_extension(import_module('.extensions.moderation', package='bot').Moderation()) | ||
|
||
client.login() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import asyncio | ||
import json | ||
from logging import getLogger | ||
from importlib import import_module | ||
import hata | ||
from hata.discord import client_core | ||
from hata import discord | ||
from hata.ext import commands | ||
from database import utils | ||
from . import constants | ||
|
||
log = getLogger(__name__) | ||
|
||
|
||
@hata.backend.KeepType(discord.Client) | ||
class Client: | ||
ready_event = asyncio.Event() | ||
_asyncio_event_loop = asyncio.get_event_loop() | ||
extensions = [] | ||
cached_guild_setups = {} | ||
|
||
def load_extension(self, ext): | ||
for method in ext._methods: | ||
method._load(ext, self) | ||
ext.__init__(self, *ext._args_, **ext._kwargs_) | ||
self.extensions.append(ext) | ||
return ext | ||
|
||
async def _ready_set(self, _): | ||
self._asyncio_event_loop.call_soon_threadsafe(self.ready_event.set) | ||
|
||
async def _add_guild_on_create(self, _, guild): | ||
asyncio.run_coroutine_threadsafe(self.get_fetch_or_create(guild.id), loop=self._asyncio_event_loop) | ||
|
||
async def _get_guild_setups(self): | ||
execute = """ | ||
SELECT * FROM guilds | ||
""" | ||
conn = self.database.conn | ||
setups = await conn.fetch(execute) | ||
for setup in setups: | ||
self._add_guild_setup(dict(setup)) | ||
|
||
def _add_guild_setup(self, setup): | ||
setup['guild_id'] = int(setup['guild_id']) | ||
if setup['log_channel_id'] is not None: | ||
setup['log_channel_id'] = int(setup['log_channel_id']) | ||
if setup['muted_role_id'] is not None: | ||
setup['muted_role_id'] = int(setup['muted_role_id']) | ||
setup['disabled_commands'] = json.loads(setup['disabled_commands']) | ||
setup['prefixes'] = json.loads(setup['prefixes']) | ||
setup['level_roles'] = json.loads(setup['level_roles']) | ||
setup['join_roles'] = json.loads(setup['join_roles']) | ||
self.cached_guild_setups[setup['guild_id']] = setup | ||
|
||
async def _create_guild_setups(self, get_after=True): | ||
await self.database.wait_until_ready() | ||
await self.ready_event.wait() | ||
await self._get_guild_setups() | ||
for guild in hata.discord.GUILDS: | ||
if guild not in self.cached_guild_setups: | ||
await utils.post_guild_setup(self, guild_id=guild) | ||
await self._get_guild_setups() | ||
|
||
def get_guild_setup(self, guild_id): | ||
return self.cached_guild_setups.get(int(guild_id)) | ||
|
||
async def fetch_guild_setup(self, guild_id): | ||
data = await utils.get_guild_setup(self, guild_id=guild_id) | ||
if data: | ||
self._add_guild_setup(data) | ||
return data | ||
|
||
async def get_fetch_or_create(self, guild_id): | ||
data = self.get_guild_setup(guild_id) | ||
if data: | ||
return data | ||
data = await self.fetch_guild_setup(guild_id) | ||
if data: | ||
return data | ||
await utils.post_guild_setup(self, guild_id=guild_id) | ||
data = await self.fetch_guild_setup(guild_id) | ||
return data | ||
|
||
async def _get_prefix(self, message): | ||
if message.guild is None: | ||
return '!' | ||
data = await self.get_fetch_or_create(message.guild.id) | ||
for prefix in data['prefixes']: | ||
if message.content.startswith(prefix): | ||
return prefix | ||
return data['prefixes'][0] | ||
|
||
def login(self, *, db=True, client=True, server=True): | ||
if client: | ||
self.events(self._ready_set, name='ready') | ||
self.events(self._add_guild_on_create, name='guild_create') | ||
self.start() | ||
if server: | ||
self._asyncio_event_loop.create_task(self.server.start()) | ||
if db: | ||
self._asyncio_event_loop.create_task(self.database.connect()) | ||
if db and client: | ||
self._asyncio_event_loop.create_task(self._create_guild_setups()) | ||
try: | ||
log.debug('Logged in, starting asyncio event loop') | ||
self._asyncio_event_loop.run_forever() | ||
except KeyboardInterrupt: | ||
log.debug('Received KeyboardInterrupt, stopping processes') | ||
self.stop() | ||
discord.client_core.KOKORO.stop() | ||
exit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import os | ||
from typing import Dict, Tuple, Union | ||
from hata import discord | ||
import json | ||
|
||
|
||
with open("config.json") as fp: | ||
config = json.load(fp) | ||
|
||
class Auth: | ||
BOT_TOKEN: str = os.environ.get("BOT_TOKEN") or config.get("BOT_TOKEN") | ||
|
||
class Colors: | ||
RED = 0xe85133 | ||
GREEN = 0x2cc95e | ||
BLUE = 0x2cb1c9 |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# simple extensions built on classes | ||
|
||
class Wrapped: | ||
def __init__(self, func, load): | ||
self.func = func | ||
self._load = load | ||
|
||
def __get__(self, instance, owner): | ||
return self.func.__get__(instance, owner) | ||
# binds the method to the instance ensuring that the | ||
# `self` argument is always passed implicitly | ||
|
||
|
||
def event(func): | ||
def load(instance, client): | ||
bound = func.__get__(instance, instance.__class__) | ||
client.events(bound) | ||
return Wrapped(func, load) | ||
|
||
|
||
def command(func): | ||
def load(instance, client): | ||
bound = func.__get__(instance, instance.__class__) | ||
client.commands(bound) | ||
return Wrapped(func, load) | ||
|
||
|
||
class ExtensionMeta(type): | ||
def __new__(cls, name, bases, dict_): | ||
klass = super().__new__(cls, name, bases, dict_) | ||
klass._methods = [] | ||
for value in dict_.values(): | ||
if isinstance(value, Wrapped): | ||
klass._methods.append(value) | ||
return klass | ||
|
||
def __call__(cls, *args, **kwargs): | ||
obj = object.__new__(cls) | ||
obj._args_ = args | ||
obj._kwargs_ = kwargs | ||
return obj | ||
|
||
|
||
class Extension(metaclass=ExtensionMeta): | ||
def remove_event(self, func): | ||
self._methods.remove(func) | ||
self.client.events.remove(func) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
from . import extension | ||
from .. import utils, constants | ||
from hata.discord import client_core | ||
from hata import backend, discord | ||
from time import time | ||
|
||
class Fun(extension.Extension): | ||
def __init__(self, client): | ||
self.client = client | ||
self.chat_grabbers = [] | ||
|
||
async def send_start_message(self, chat_grabber: utils.ChatGrabber): | ||
embed = discord.Embed(color=constants.Colors.BLUE, description='Say hi, you\'re talking to people in **{}**'.format(chat_grabber.destination.guild)) | ||
await self.client.message_create(chat_grabber.origin, embed=embed) | ||
embed = discord.Embed(color=constants.Colors.BLUE, description='Say hi, you\'re talking to people in **{}**'.format(chat_grabber.origin.guild)) | ||
await self.client.message_create(chat_grabber.destination, embed=embed) | ||
|
||
async def send_stop_message(self, chat_grabber: utils.ChatGrabber): | ||
embed = discord.Embed(color=constants.Colors.BLUE, description='You\'re no longer talking to people in **{}**'.format(chat_grabber.destination.guild)) | ||
await self.client.message_create(chat_grabber.origin, embed=embed) | ||
embed = discord.Embed(color=constants.Colors.BLUE, description='You\'re no longer talking to people in **{}**'.format(chat_grabber.origin.guild)) | ||
await self.client.message_create(chat_grabber.destination, embed=embed) | ||
|
||
async def create_chat(self, message): | ||
if any(message.channel in (c.origin, c.destination) for c in self.chat_grabbers): | ||
await self.client.message_create(message.channel, 'This channel is already chatting.') | ||
return | ||
try: | ||
chat_grabber = next(c for c in self.chat_grabbers if not c.started) | ||
chat_grabber.set_destination(message.channel) | ||
await chat_grabber.start() | ||
except StopIteration: | ||
embed = discord.Embed(color=constants.Colors.BLUE, description='**Looking for someone who wants to talk to you**') | ||
await self.client.message_create(message.channel, content=message.author.mention, embed=embed) | ||
chat_grabber = utils.ChatGrabber( | ||
self.client, | ||
message.channel, | ||
timeout=30, | ||
start_hook=self.send_start_message, | ||
stop_hook=self.send_stop_message, | ||
destination_to_origin=True | ||
) | ||
self.chat_grabbers.append(chat_grabber) | ||
backend.future_or_timeout(chat_grabber.destination_future, 30) | ||
try: | ||
await chat_grabber.destination_future | ||
except TimeoutError: | ||
embed = discord.Embed(color=constants.Colors.RED, description=':x: **No one wants to talk to you**') | ||
await self.client.message_create(message.channel, content=message.author.mention, embed=embed) | ||
self.chat_grabbers.remove(chat_grabber) | ||
return | ||
|
||
async def close_chat(self, message): | ||
try: | ||
chat_grabber = next(c for c in self.chat_grabbers if message.channel in (c.origin, c.destination)) | ||
except StopIteration: | ||
await self.client.message_create(message.channel, 'This channel isn\'t chatting') | ||
return | ||
if message.author in chat_grabber.cancellation_votes: | ||
await self.client.message_create(message.channel, 'You\'ve already voted to close this chat.') | ||
return | ||
users = list(filter((lambda key: time() - chat_grabber.users[key]['time'] < 30), chat_grabber.users)) | ||
if message.author.id not in users: | ||
return | ||
elif len(chat_grabber.cancellation_votes) >= len(users) - 1: | ||
await chat_grabber.stop() | ||
self.chat_grabbers.remove(chat_grabber) | ||
else: | ||
chat_grabber.cancellation_votes.append(message.author) | ||
await self.client.message_create(message.channel, '{}/{} votes required to close this chat.'.format(chat_grabber.cancellation_votes, len(users))) | ||
|
||
@extension.command | ||
async def chat(self, client, message, arg=None): | ||
if arg is None: | ||
await self.create_chat(message) | ||
elif arg.lower() == 'close': | ||
await self.close_chat(message) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from . import extension | ||
from .. import constants | ||
from .. import utils | ||
from hata import discord | ||
from database import utils as dutils | ||
|
||
|
||
class Main(extension.Extension): | ||
def __init__(self, client): | ||
self.client = client | ||
|
||
@extension.event | ||
async def ready(self, client): | ||
print('Logged in as {}'.format(self.client.full_name)) | ||
|
||
@extension.command | ||
async def ping(self, client, message): | ||
embed = discord.Embed( | ||
color=constants.Colors.BLUE, | ||
title='Pong', | ||
description=':ping_pong: **WebSocket:**' | ||
' {:.4f}ms'.format(self.client.gateway.latency * 1000) | ||
) | ||
await self.client.message_create(message.channel, embed=embed) | ||
|
||
@extension.command | ||
async def setlog(self, client, message, channel: discord.ChannelText): | ||
data = await utils.hata_fut_from_asyncio_task( | ||
self.client, | ||
self.client.get_fetch_or_create(message.guild.id) | ||
) | ||
data['log_channel_id'] = channel.id | ||
await utils.hata_fut_from_asyncio_task( | ||
self.client, | ||
dutils.update_guild_setup( | ||
self.client, | ||
guild_id=message.guild.id, | ||
log_channel_id=channel.id | ||
) | ||
) | ||
embed = discord.Embed(color=constants.Colors.GREEN, description='Changed log channel to {}'.format(channel.mention)) | ||
await self.client.message_create(message.channel, embed=embed) |
Oops, something went wrong.