forked from Minecraft/minecraft_manager
Updates to API and Discord (#28)
parent
da66751986
commit
773efe0606
21
api/api.py
21
api/api.py
|
@ -22,14 +22,19 @@ PLUGIN_DEMOTE = 'demote'
|
||||||
|
|
||||||
|
|
||||||
def plugin(key, command):
|
def plugin(key, command):
|
||||||
host = '127.0.0.1'
|
try:
|
||||||
port = getattr(settings, 'PLUGIN_PORT', None)
|
host = '127.0.0.1'
|
||||||
full_command = "{0} {1}".format(key, command)
|
port = getattr(settings, 'PLUGIN_PORT', None)
|
||||||
if port and plugin_exists():
|
full_command = "{0} {1}".format(key, command)
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
if port and plugin_exists():
|
||||||
sock.connect((host, port))
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
sock.sendall(full_command.encode('utf-8'))
|
sock.connect((host, port))
|
||||||
sock.close()
|
sock.sendall(full_command.encode('utf-8'))
|
||||||
|
sock.close()
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def discord_mcm(message='', embeds=None, ping=False):
|
def discord_mcm(message='', embeds=None, ping=False):
|
||||||
|
|
212
api/bot.py
212
api/bot.py
|
@ -1,212 +0,0 @@
|
||||||
import discord, logging, re, sys, traceback, asyncio
|
|
||||||
from minecraft_manager.models import Application, Player
|
|
||||||
from minecraft_manager.api import api
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import close_old_connections
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class Discord(discord.Client):
|
|
||||||
discord_game = 'MCM'
|
|
||||||
prefix = getattr(settings, 'DISCORD_BOT_PREFIX', '!')
|
|
||||||
auth_roles = getattr(settings, 'DISCORD_BOT_ROLES', [])
|
|
||||||
error_users = getattr(settings, 'DISCORD_ERROR_USERS', [])
|
|
||||||
new_member_roles = getattr(settings, 'DISCORD_BOT_NEW_MEMBER_ROLES', [])
|
|
||||||
token = None
|
|
||||||
|
|
||||||
def __init__(self, token, **kwargs):
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
self.token = token
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def on_ready(self):
|
|
||||||
print('Logged in as')
|
|
||||||
print(self.user.name)
|
|
||||||
print(self.user.id)
|
|
||||||
print(discord.__version__)
|
|
||||||
print('Voice Loaded: {0}'.format(discord.opus.is_loaded()))
|
|
||||||
print('OAuth URL: https://discordapp.com/api/oauth2/authorize?client_id={0}&permissions=0&scope=bot'.format(self.user.id))
|
|
||||||
print('------')
|
|
||||||
logger.info('Logged in as {0} ({1}) with discord.py v{2}'.format(self.user.name, self.user.id, discord.__version__))
|
|
||||||
yield from self.change_presence(game=discord.Game(name=self.discord_game))
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def discord_message(self, channel, message):
|
|
||||||
if isinstance(message, discord.Embed):
|
|
||||||
for idx, field in enumerate(message.fields):
|
|
||||||
if not field.value:
|
|
||||||
message.set_field_at(idx, name=field.name, value="N/A")
|
|
||||||
yield from self.send_message(channel, embed=message)
|
|
||||||
else:
|
|
||||||
yield from self.send_message(channel, message)
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def on_message(self, message):
|
|
||||||
|
|
||||||
# IGNORE DM AND BOTS
|
|
||||||
if message.author.bot is True or message.channel.is_private is True:
|
|
||||||
return
|
|
||||||
|
|
||||||
member_roles = [role.id for role in message.author.roles]
|
|
||||||
|
|
||||||
# FIX STALE DB CONNECTIONS
|
|
||||||
close_old_connections()
|
|
||||||
|
|
||||||
|
|
||||||
# IF MEMBER IS NOT AUTHORIZED, IGNORE
|
|
||||||
if not any(role in self.auth_roles for role in member_roles):
|
|
||||||
return
|
|
||||||
|
|
||||||
# HELP
|
|
||||||
match = re.match("[{0}]help$".format(self.prefix), message.content)
|
|
||||||
if match:
|
|
||||||
embed = discord.Embed(colour=discord.Colour(0x417505))
|
|
||||||
embed.set_thumbnail(url="https://cdn.discordapp.com/avatars/454457830918062081/b5792489bc43d9e17b8f657880a17dd4.png")
|
|
||||||
embed.add_field(name="Minecraft Manager Help", value="-----------------------------")
|
|
||||||
embed.add_field(name="{}[app ]search <username>".format(self.prefix), value="Search for applications by partial or exact username.")
|
|
||||||
embed.add_field(name="{}[app ]info <app ID>".format(self.prefix), value="Get detailed information about a specific application.")
|
|
||||||
embed.add_field(name="{}[app ]accept|deny <app ID>".format(self.prefix), value="Take action on an application.")
|
|
||||||
embed.add_field(name="{}demote <username>".format(self.prefix), value="Demote a player to the role given to accepted applications.")
|
|
||||||
embed.add_field(name="{}compare".format(self.prefix), value="Compare Discord users to the Whitelist.")
|
|
||||||
yield from self.discord_message(message.channel, embed)
|
|
||||||
# APP COMMANDS WITH APP ID
|
|
||||||
match = re.match("[{0}](?:app )?(i|info|a|accept|d|deny) (\d+)$".format(self.prefix), message.content)
|
|
||||||
if match:
|
|
||||||
if match.group(1) and match.group(2):
|
|
||||||
action = match.group(1)[:1]
|
|
||||||
action_display = "accept" if action == "a" else "deny" if action == "d" else ""
|
|
||||||
application = None
|
|
||||||
try:
|
|
||||||
application = Application.objects.get(id=match.group(2))
|
|
||||||
except:
|
|
||||||
yield from self.discord_message(message.channel, "An Application with that ID doesn't exist.")
|
|
||||||
return
|
|
||||||
if action == "i":
|
|
||||||
# Info
|
|
||||||
msg = self.build_info(application)
|
|
||||||
else:
|
|
||||||
# Action
|
|
||||||
accept = True if action == "a" else False
|
|
||||||
if not application.accepted:
|
|
||||||
application.accepted = accept
|
|
||||||
application.save()
|
|
||||||
if Player.objects.filter(username__iexact=application.username).exists():
|
|
||||||
player = Player.objects.get(username__iexact=application.username)
|
|
||||||
player.application_id = application.id
|
|
||||||
player.save()
|
|
||||||
msg = "App ID **{0}** was successfully {1}.".format(match.group(2), "accepted" if accept else "denied")
|
|
||||||
api.plugin("accept" if accept else "deny", application.username)
|
|
||||||
else:
|
|
||||||
msg = "App ID **{0}** was already {1}.".format(match.group(2), "accepted" if application.accepted else "denied")
|
|
||||||
yield from self.discord_message(message.channel, msg)
|
|
||||||
return
|
|
||||||
# APP INFO WITH PARTIAL NAME SEARCH
|
|
||||||
match = re.match("[{0}](?:app )?(?:search|info) (\S+)?$".format(self.prefix), message.content)
|
|
||||||
if match:
|
|
||||||
search = match.group(1)
|
|
||||||
applications = Application.objects.filter(username__icontains=search)[:10]
|
|
||||||
count = Application.objects.filter(username__icontains=search).count()
|
|
||||||
if count > 0:
|
|
||||||
if count == 1:
|
|
||||||
info = self.build_info(applications[0])
|
|
||||||
else:
|
|
||||||
info = "**Found the following applications**"
|
|
||||||
for app in applications:
|
|
||||||
info += "\n{0} - {1} ({2})".format(app.id, app.username.replace("_", "\\_"), app.status)
|
|
||||||
if count > 10:
|
|
||||||
info += "\n**This is only 10 applications out of {0} found. Please narrow your search if possible.**".format(
|
|
||||||
len(applications))
|
|
||||||
else:
|
|
||||||
players = Player.objects.filter(username__icontains=search, application__isnull=False)[:10]
|
|
||||||
count = Player.objects.filter(username__icontains=search, application__isnull=False).count()
|
|
||||||
if count > 0:
|
|
||||||
if count == 1:
|
|
||||||
yield from self.discord_message(message.channel, "**No applications matched, however there is a player match**")
|
|
||||||
info = self.build_info(players[0].application)
|
|
||||||
else:
|
|
||||||
info = "**No applications matched, however there are player matches**"
|
|
||||||
for player in players:
|
|
||||||
app = player.application
|
|
||||||
info += "\n{0} - {1} AKA {2} ({3})".format(app.id, app.username.replace("_", "\\_"), player.username.replace("_", "\\_"), app.status)
|
|
||||||
if count > 10:
|
|
||||||
info += "\n**This is only 10 players out of {0} found. Please narrow your search if possible.**".format(
|
|
||||||
len(players))
|
|
||||||
else:
|
|
||||||
info = "No applications matched that search."
|
|
||||||
yield from self.discord_message(message.channel, info)
|
|
||||||
# DEMOTE A PLAYER TO MEMBER
|
|
||||||
match = re.match("[{0}]demote (\w+)$".format(self.prefix), message.content)
|
|
||||||
if match:
|
|
||||||
yield from self.delete_message(message)
|
|
||||||
username = match.group(1)
|
|
||||||
api.plugin(api.PLUGIN_DEMOTE, username)
|
|
||||||
deactivated = ""
|
|
||||||
if User.objects.filter(username__iexact=username).exists():
|
|
||||||
user = User.objects.get(username__iexact=username)
|
|
||||||
user.is_active = False
|
|
||||||
user.save()
|
|
||||||
deactivated = " and de-activated"
|
|
||||||
yield from self.discord_message(message.channel, "{} has been demoted{}.".format(username, deactivated))
|
|
||||||
# COMPARE DISCORD USERS TO WHITELIST
|
|
||||||
match = re.match("[{0}]compare".format(self.prefix), message.content)
|
|
||||||
if match:
|
|
||||||
yield from self.delete_message(message)
|
|
||||||
yield from self.send_typing(message.channel)
|
|
||||||
no_player = []
|
|
||||||
no_application = []
|
|
||||||
for member in message.server.members:
|
|
||||||
if member.bot:
|
|
||||||
continue
|
|
||||||
name = member.nick if member.nick else member.name
|
|
||||||
try:
|
|
||||||
Player.objects.get(username__iexact=name)
|
|
||||||
except:
|
|
||||||
no_player.append(name)
|
|
||||||
try:
|
|
||||||
Application.objects.get(username__iexact=name)
|
|
||||||
except:
|
|
||||||
no_player = no_player[:-1]
|
|
||||||
no_application.append(name)
|
|
||||||
header = "**The following users have an application match, but no player match on the whitelist:**\n"
|
|
||||||
yield from self.discord_message(message.author, "{}```{}```".format(header, "\n".join(no_player)))
|
|
||||||
header = "**The following users do not have an application or player match on the whitelist:**\n"
|
|
||||||
yield from self.discord_message(message.author, "{}```{}```".format(header, "\n".join(no_application)))
|
|
||||||
|
|
||||||
def build_info(self, application):
|
|
||||||
embed = discord.Embed(colour=discord.Colour(0x417505))
|
|
||||||
embed.set_thumbnail(
|
|
||||||
url="https://minotar.net/helm/{0}/100.png".format(application.username))
|
|
||||||
embed.add_field(name="Application ID", value=application.id)
|
|
||||||
embed.add_field(name="Username", value=application.username.replace("_", "\\_"))
|
|
||||||
embed.add_field(name="Age", value=application.age)
|
|
||||||
embed.add_field(name="Type of Player", value=application.player_type)
|
|
||||||
embed.add_field(name="Ever been banned", value=application.ever_banned)
|
|
||||||
if application.ever_banned:
|
|
||||||
embed.add_field(name="Reason for being banned", value=application.ever_banned_explanation)
|
|
||||||
embed.add_field(name="Reference", value=application.reference)
|
|
||||||
embed.add_field(name="Read the Rules", value=application.read_rules)
|
|
||||||
embed.add_field(name="Date", value=application.date_display)
|
|
||||||
embed.add_field(name="Status", value=application.status)
|
|
||||||
return embed
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def on_error(self, event, *args, **kwargs):
|
|
||||||
print(sys.exc_info())
|
|
||||||
print("Exception raised by " + event)
|
|
||||||
error = '{0}\n{1}'.format(sys.exc_info()[1], ''.join(traceback.format_tb(sys.exc_info()[2])))
|
|
||||||
logger.error(error)
|
|
||||||
for user in self.error_users:
|
|
||||||
try:
|
|
||||||
user = discord.User(id=user)
|
|
||||||
yield from self.discord_message(user, '```python\n{}```'.format(error))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def run_bot(self):
|
|
||||||
self.run(self.token)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -138,11 +138,11 @@ class WebAPI(View):
|
||||||
|
|
||||||
def access_level(self, user):
|
def access_level(self, user):
|
||||||
access = {'cpp': False, 'cpf': False, 'cpa': False}
|
access = {'cpp': False, 'cpf': False, 'cpa': False}
|
||||||
if user.has_perm('auth.coreprotect_partial'):
|
if user.has_perm('minecraft_manager.coreprotect_partial'):
|
||||||
access['cpp'] = True
|
access['cpp'] = True
|
||||||
if user.has_perm('auth.coreprotect_full'):
|
if user.has_perm('minecraft_manager.coreprotect_full'):
|
||||||
access['cpf'] = True
|
access['cpf'] = True
|
||||||
if user.has_perm('auth.coreprotect_activity'):
|
if user.has_perm('minecraft_manager.coreprotect_activity'):
|
||||||
access['cpa'] = True
|
access['cpa'] = True
|
||||||
return access
|
return access
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import os, sys, django
|
import os
|
||||||
|
import sys
|
||||||
|
import django
|
||||||
|
|
||||||
sep = os.sep
|
sep = os.sep
|
||||||
path = os.path.dirname(os.path.abspath(__file__))
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
@ -11,8 +13,9 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{}.settings".format(project))
|
||||||
django.setup()
|
django.setup()
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from minecraft_manager.api.bot import Discord
|
from minecraft_manager.bot.discord import Discord
|
||||||
|
|
||||||
token = getattr(settings, 'DISCORD_BOT_TOKEN', None)
|
token = getattr(settings, 'DISCORD_BOT_TOKEN', None)
|
||||||
bot = Discord(token)
|
bot = Discord(token)
|
||||||
|
|
||||||
bot.run_bot()
|
bot.run_bot()
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
You will need to get this from your CP MySQL tables
|
|
||||||
|
|
||||||
NOTE: CoreProtect does not match up these IDs with the block's in-game ID, so air is not 0, stone is not 1, etc.
|
|
||||||
|
|
||||||
1. mysql -p <coreprotect database> -e "SELECT id, material FROM co_material_map" > blocks.txt
|
|
||||||
2. Open blocks.txt
|
|
||||||
3. Remove the header row
|
|
||||||
4. Remove spaces/tabs and delimit with a ','
|
|
||||||
e.g. 1,minecraft:air
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from minecraft_manager.api import api
|
||||||
|
from minecraft_manager.bot.utils import get_application, build_info
|
||||||
|
from minecraft_manager.models import Application, Player
|
||||||
|
|
||||||
|
|
||||||
|
class Commands(commands.Cog):
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
async def cog_check(self, ctx):
|
||||||
|
# No DMs
|
||||||
|
if ctx.guild is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check roles
|
||||||
|
if not hasattr(ctx.author, "roles"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
for role in ctx.author.roles:
|
||||||
|
for auth_role in self.bot.auth_roles:
|
||||||
|
if role.id == auth_role:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_superuser(self, member: discord.Member):
|
||||||
|
for role in member.roles:
|
||||||
|
for auth_role in self.bot.superuser_roles:
|
||||||
|
if role.id == auth_role:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def help(self, ctx):
|
||||||
|
embed = discord.Embed(colour=discord.Colour(0x417505))
|
||||||
|
embed.set_thumbnail(
|
||||||
|
url="https://cdn.discordapp.com/avatars/454457830918062081/b5792489bc43d9e17b8f657880a17dd4.png")
|
||||||
|
embed.add_field(name="Minecraft Manager Help", value="-----------------------------")
|
||||||
|
embed.add_field(name="{}app search <username>".format(self.bot.prefix),
|
||||||
|
value="Search for applications by partial or exact username.")
|
||||||
|
embed.add_field(name="{}app info <app ID>".format(self.bot.prefix),
|
||||||
|
value="Get detailed information about a specific application.")
|
||||||
|
embed.add_field(name="{}app accept|deny <app ID>".format(self.bot.prefix), value="Take action on an application.")
|
||||||
|
embed.add_field(name="{}demote <username>".format(self.bot.prefix),
|
||||||
|
value="Demote a player to the role given to accepted applications.")
|
||||||
|
embed.add_field(name="{}compare".format(self.bot.prefix), value="Compare Discord users to the Whitelist.")
|
||||||
|
await self.bot.discord_message(ctx.message.channel, embed)
|
||||||
|
|
||||||
|
@commands.group("app", aliases=["application"])
|
||||||
|
async def app(self, ctx):
|
||||||
|
if ctx.invoked_subcommand is None:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "No sub-command supplied. Info, Search, Accept, or Deny.")
|
||||||
|
|
||||||
|
@app.command("info")
|
||||||
|
async def _info(self, ctx, *args):
|
||||||
|
if len(args) == 0:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "Info requires an application ID or username.")
|
||||||
|
|
||||||
|
key = args[0]
|
||||||
|
is_id = True
|
||||||
|
try:
|
||||||
|
int(key)
|
||||||
|
except:
|
||||||
|
is_id = False
|
||||||
|
|
||||||
|
if is_id:
|
||||||
|
application = get_application(key)
|
||||||
|
if not application:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "An Application with that ID doesn't exist.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
found = False
|
||||||
|
applications = Application.objects.filter(username__icontains=key)
|
||||||
|
if len(applications) == 0:
|
||||||
|
applications = Application.objects.filter(player__username__icontains=key)
|
||||||
|
if len(applications) == 1:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "**No applications matched, however there is a player match**")
|
||||||
|
application = applications[0]
|
||||||
|
found = True
|
||||||
|
elif len(applications) == 1:
|
||||||
|
application = applications[0]
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "An exact Application could not be found. Try search instead.")
|
||||||
|
return
|
||||||
|
await self.bot.discord_message(ctx.message.channel, build_info(application))
|
||||||
|
|
||||||
|
@app.command("accept")
|
||||||
|
async def _accept(self, ctx, app_id: int):
|
||||||
|
application = get_application(app_id)
|
||||||
|
if not application:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "An Application with that ID doesn't exist.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not application.accepted:
|
||||||
|
application.accepted = True
|
||||||
|
application.save()
|
||||||
|
if Player.objects.filter(username__iexact=application.username).exists():
|
||||||
|
player = Player.objects.get(username__iexact=application.username)
|
||||||
|
player.application_id = application.id
|
||||||
|
player.save()
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "App ID **{0}** was successfully accepted.".format(app_id))
|
||||||
|
if not api.plugin(api.PLUGIN_ACCEPT, application.username):
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "Could not accept in-game, is the server running?")
|
||||||
|
|
||||||
|
@app.command("deny")
|
||||||
|
async def _deny(self, ctx, app_id: int):
|
||||||
|
application = get_application(app_id)
|
||||||
|
if not application:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "An Application with that ID doesn't exist.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not application.accepted:
|
||||||
|
application.accepted = False
|
||||||
|
application.save()
|
||||||
|
if Player.objects.filter(username__iexact=application.username).exists():
|
||||||
|
player = Player.objects.get(username__iexact=application.username)
|
||||||
|
player.application_id = application.id
|
||||||
|
player.save()
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "App ID **{0}** was successfully denied.".format(app_id))
|
||||||
|
if not api.plugin(api.PLUGIN_DENY, application.username):
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "Could not deny in-game, is the server running?")
|
||||||
|
|
||||||
|
@app.command("search")
|
||||||
|
async def _search(self, ctx, search: str):
|
||||||
|
applications = Application.objects.filter(username__icontains=search)[:10]
|
||||||
|
count = Application.objects.filter(username__icontains=search).count()
|
||||||
|
if count > 0:
|
||||||
|
if count == 1:
|
||||||
|
info = build_info(applications[0])
|
||||||
|
else:
|
||||||
|
info = "**Found the following applications**"
|
||||||
|
for app in applications:
|
||||||
|
info += "\n{0} - {1} ({2})".format(app.id, app.username.replace("_", "\\_"), app.status)
|
||||||
|
if count > 10:
|
||||||
|
info += "\n**This is only 10 applications out of {0} found. Please narrow your search if possible.**".format(len(applications))
|
||||||
|
else:
|
||||||
|
players = Player.objects.filter(username__icontains=search, application__isnull=False)[:10]
|
||||||
|
count = Player.objects.filter(username__icontains=search, application__isnull=False).count()
|
||||||
|
if count > 0:
|
||||||
|
if count == 1:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "**No applications matched, however there is a player match**")
|
||||||
|
info = build_info(players[0].application)
|
||||||
|
else:
|
||||||
|
info = "**No applications matched, however there are player matches**"
|
||||||
|
for player in players:
|
||||||
|
app = player.application
|
||||||
|
info += "\n{0} - {1} AKA {2} ({3})".format(app.id, app.username.replace("_", "\\_"),
|
||||||
|
player.username.replace("_", "\\_"), app.status)
|
||||||
|
if count > 10:
|
||||||
|
info += "\n**This is only 10 players out of {0} found. Please narrow your search if possible.**".format(len(players))
|
||||||
|
else:
|
||||||
|
info = "No applications matched that search."
|
||||||
|
await self.bot.discord_message(ctx.message.channel, info)
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def demote(self, ctx, username: str):
|
||||||
|
if not self.is_superuser(ctx.author):
|
||||||
|
return
|
||||||
|
await ctx.message.delete()
|
||||||
|
if api.plugin(api.PLUGIN_DEMOTE, username):
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "{} has been demoted in-game.".format(username))
|
||||||
|
else:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "{} could not be demoted in-game, is the server running?".format(username))
|
||||||
|
if User.objects.filter(username__iexact=username).exists():
|
||||||
|
user = User.objects.get(username__iexact=username)
|
||||||
|
user.is_active = False
|
||||||
|
user.save()
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "{} has been de-activated in MCM.".format(username))
|
||||||
|
else:
|
||||||
|
await self.bot.discord_message(ctx.message.channel, "{} could not be found in MCM, is their account up-to-date?".format(username))
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def compare(self, ctx):
|
||||||
|
await ctx.message.delete()
|
||||||
|
await ctx.message.channel.trigger_typing()
|
||||||
|
no_player = []
|
||||||
|
no_application = []
|
||||||
|
for member in ctx.message.guild.members:
|
||||||
|
if member.bot:
|
||||||
|
continue
|
||||||
|
name = member.nick if member.nick else member.name
|
||||||
|
try:
|
||||||
|
Player.objects.get(username__iexact=name)
|
||||||
|
except:
|
||||||
|
no_player.append(name)
|
||||||
|
try:
|
||||||
|
Application.objects.get(username__iexact=name)
|
||||||
|
except:
|
||||||
|
no_player = no_player[:-1]
|
||||||
|
no_application.append(name)
|
||||||
|
if no_player:
|
||||||
|
header = "**The following users have an application match, but no player match on the whitelist:**\n"
|
||||||
|
await self.bot.discord_message(ctx.author, "{}```{}```".format(header, "\n".join(no_player)))
|
||||||
|
if no_application:
|
||||||
|
header = "**The following users do not have an application or player match on the whitelist:**\n"
|
||||||
|
await self.bot.discord_message(ctx.author, "{}```{}```".format(header, "\n".join(no_application)))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Commands(bot))
|
|
@ -0,0 +1,80 @@
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import close_old_connections
|
||||||
|
|
||||||
|
from minecraft_manager.bot.commands import Commands
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
description = '''
|
||||||
|
A Discord bot connected to an MCM instance.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class Discord(commands.Bot):
|
||||||
|
discord_game = 'MCM'
|
||||||
|
prefix = getattr(settings, 'DISCORD_BOT_PREFIX', '!')
|
||||||
|
auth_roles = getattr(settings, 'DISCORD_BOT_ROLES', [])
|
||||||
|
superuser_roles = getattr(settings, 'DISCORD_SUPERUSER_ROLES', [])
|
||||||
|
error_users = getattr(settings, 'DISCORD_ERROR_USERS', [])
|
||||||
|
|
||||||
|
def __init__(self, token):
|
||||||
|
super().__init__(command_prefix=self.prefix, description=description, case_insensitive=True, help_command=None, activity=discord.Game(name=self.discord_game))
|
||||||
|
self.token = token
|
||||||
|
self.load_extension("minecraft_manager.bot.commands")
|
||||||
|
|
||||||
|
async def on_ready(self):
|
||||||
|
print('Logged in as')
|
||||||
|
print(self.user.name)
|
||||||
|
print(self.user.id)
|
||||||
|
print(discord.__version__)
|
||||||
|
print('Voice Loaded: {0}'.format(discord.opus.is_loaded()))
|
||||||
|
print('OAuth URL: https://discordapp.com/api/oauth2/authorize?client_id={0}&permissions=0&scope=bot'.format(self.user.id))
|
||||||
|
print('------')
|
||||||
|
print('Logged in as {0} ({1}) with discord.py v{2}'.format(self.user.name, self.user.id, discord.__version__))
|
||||||
|
|
||||||
|
async def discord_message(self, dest, message):
|
||||||
|
if isinstance(message, discord.Embed):
|
||||||
|
for idx, field in enumerate(message.fields):
|
||||||
|
if not field.value:
|
||||||
|
message.set_field_at(idx, name=field.name, value="N/A")
|
||||||
|
await dest.send(embed=message)
|
||||||
|
else:
|
||||||
|
await dest.send(message)
|
||||||
|
|
||||||
|
async def before_invoke(self, coro):
|
||||||
|
# FIX STALE DB CONNECTIONS
|
||||||
|
close_old_connections()
|
||||||
|
|
||||||
|
async def on_command_error(self, context, exception):
|
||||||
|
if not isinstance(exception, commands.CommandInvokeError):
|
||||||
|
return
|
||||||
|
if hasattr(exception, "original"):
|
||||||
|
error = ''.join(traceback.format_tb(exception.original.__traceback__))
|
||||||
|
else:
|
||||||
|
error = exception
|
||||||
|
logger.error(error)
|
||||||
|
for user_id in self.error_users:
|
||||||
|
user = self.get_user(user_id)
|
||||||
|
if user:
|
||||||
|
await self.discord_message(user, '```python\n{}```'.format(error))
|
||||||
|
|
||||||
|
def run_bot(self):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
|
try:
|
||||||
|
loop.run_until_complete(self.start(self.token))
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info("Bot received keyboard interrupt")
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
logger.info('Bot encountered the following unhandled exception %s', e)
|
||||||
|
finally:
|
||||||
|
loop.run_until_complete(self.logout())
|
||||||
|
logger.info("Bot shutting down...")
|
|
@ -0,0 +1,27 @@
|
||||||
|
import discord
|
||||||
|
from minecraft_manager.models import Application, Player
|
||||||
|
|
||||||
|
|
||||||
|
def build_info(application):
|
||||||
|
embed = discord.Embed(colour=discord.Colour(0x417505))
|
||||||
|
embed.set_thumbnail(
|
||||||
|
url="https://minotar.net/helm/{0}/100.png".format(application.username))
|
||||||
|
embed.add_field(name="Application ID", value=application.id)
|
||||||
|
embed.add_field(name="Username", value=application.username.replace("_", "\\_"))
|
||||||
|
embed.add_field(name="Age", value=application.age)
|
||||||
|
embed.add_field(name="Type of Player", value=application.player_type)
|
||||||
|
embed.add_field(name="Ever been banned", value=application.ever_banned)
|
||||||
|
if application.ever_banned:
|
||||||
|
embed.add_field(name="Reason for being banned", value=application.ever_banned_explanation)
|
||||||
|
embed.add_field(name="Reference", value=application.reference)
|
||||||
|
embed.add_field(name="Read the Rules", value=application.read_rules)
|
||||||
|
embed.add_field(name="Date", value=application.date_display)
|
||||||
|
embed.add_field(name="Status", value=application.status)
|
||||||
|
return embed
|
||||||
|
|
||||||
|
|
||||||
|
def get_application(app_id):
|
||||||
|
try:
|
||||||
|
return Application.objects.get(id=app_id)
|
||||||
|
except:
|
||||||
|
return None
|
|
@ -31,8 +31,8 @@ def get_sidebar(current_app, request):
|
||||||
ret += '<li {}><a href="{}"><span class="glyphicon glyphicon-wrench"></span> Report</a></li>'.format('class="active"' if current_app == 'report' else '', reverse('report'))
|
ret += '<li {}><a href="{}"><span class="glyphicon glyphicon-wrench"></span> Report</a></li>'.format('class="active"' if current_app == 'report' else '', reverse('report'))
|
||||||
|
|
||||||
show_chat = True if getattr(settings, 'GLOBAL_LOG', None) is not None else False
|
show_chat = True if getattr(settings, 'GLOBAL_LOG', None) is not None else False
|
||||||
if show_chat and request.user.has_perm('auth.chat'):
|
if show_chat and request.user.has_perm('minecraft_manager.chat'):
|
||||||
ret += '<li {}><a href="{}"><span class="glyphicon glyphicon-comment"></span> Chat</a></li>'.format('class="active"' if current_app == 'chat' else '', reverse('chat'))
|
ret += '<li {}><a href="{}"><span class="glyphicon glyphicon-comment"></span> Chat</a></li>'.format('class="active"' if current_app == 'chat' else '', reverse('chat'))
|
||||||
if request.user.has_perm('auth.bots'):
|
if request.user.has_perm('minecraft_manager.bots'):
|
||||||
ret += '<li {}><a href="{}"><span class="glyphicon glyphicon-flash"></span> Bots</a></li>'.format('class="active"' if current_app == 'bots' else '', reverse('bots'))
|
ret += '<li {}><a href="{}"><span class="glyphicon glyphicon-flash"></span> Bots</a></li>'.format('class="active"' if current_app == 'bots' else '', reverse('bots'))
|
||||||
return ret
|
return ret
|
||||||
|
|
6
urls.py
6
urls.py
|
@ -1,6 +1,6 @@
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
import minecraft_manager.views as mcm
|
import minecraft_manager.views as mcm
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -33,9 +33,9 @@ urlpatterns = [
|
||||||
#Report
|
#Report
|
||||||
url(r'^report/$', login_required(mcm.Report.as_view()), name="report"),
|
url(r'^report/$', login_required(mcm.Report.as_view()), name="report"),
|
||||||
#Chat
|
#Chat
|
||||||
url(r'^dashboard/chat/$', login_required(mcm.Chat.as_view()), name="chat"),
|
url(r'^dashboard/chat/$', permission_required('minecraft_manager.chat')(mcm.Chat.as_view()), name="chat"),
|
||||||
#Bots
|
#Bots
|
||||||
url(r'^dashboard/bots/$', login_required(mcm.Bots.as_view()), name="bots"),
|
url(r'^dashboard/bots/$', permission_required('minecraft_manager.bots')(mcm.Bots.as_view()), name="bots"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue