Added command API and bot
+Rewrote all of Geoffrey's commands for Django +Command api allows all the geoffrey commands to be accessed though a REST API +Added foundation for getting bot to work, no commands at the momentdoc_update
parent
7748ab4010
commit
803d25d67f
|
@ -0,0 +1,87 @@
|
||||||
|
class DataBaseError(Exception):
|
||||||
|
"""Base class for exceptions in this module."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LocationInitError(DataBaseError):
|
||||||
|
"""Error in initializing Location"""
|
||||||
|
|
||||||
|
|
||||||
|
class TunnelInitError(DataBaseError):
|
||||||
|
"""Error in initializing Tunnel"""
|
||||||
|
|
||||||
|
|
||||||
|
class NoMatchFoundError(DataBaseError):
|
||||||
|
"""No matches were found in the database"""
|
||||||
|
|
||||||
|
|
||||||
|
class LocationLookUpError(DataBaseError):
|
||||||
|
"""Error in finding location in database"""
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteEntryError(DataBaseError):
|
||||||
|
"""Error in deleting entry"""
|
||||||
|
|
||||||
|
|
||||||
|
class UsernameLookupFailed(Exception):
|
||||||
|
"""Error in username lookup, is the player's nickname set correctly? *stares at aeskdar*"""
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerNotFound(DataBaseError):
|
||||||
|
"""Player not found in database."""
|
||||||
|
|
||||||
|
|
||||||
|
class EntryNameNotUniqueError(DataBaseError):
|
||||||
|
"""A location by that name is already in the database."""
|
||||||
|
|
||||||
|
|
||||||
|
class StringTooLong(DataBaseError):
|
||||||
|
"""Given string is too long."""
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseValueError(DataBaseError):
|
||||||
|
"""'String too long or number too large"""
|
||||||
|
|
||||||
|
|
||||||
|
class ItemNotFound(DataBaseError):
|
||||||
|
"""No item matches found in database"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidDimError(DataBaseError):
|
||||||
|
"""Invalid dimension name"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidTunnelError(DataBaseError):
|
||||||
|
"""Invalid tunnel name"""
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerInDBError(DataBaseError):
|
||||||
|
"""Player already registered in database"""
|
||||||
|
|
||||||
|
|
||||||
|
class LocationHasTunnelError(DataBaseError):
|
||||||
|
"""That location already has a tunnel"""
|
||||||
|
|
||||||
|
|
||||||
|
class NoPermissionError(DataBaseError):
|
||||||
|
"""You have no permission to run this command"""
|
||||||
|
|
||||||
|
|
||||||
|
class NotOnServerError(DataBaseError):
|
||||||
|
"""You need to run this command on 24CC"""
|
||||||
|
|
||||||
|
|
||||||
|
class NoLocationsInDatabase(DataBaseError):
|
||||||
|
"""This player has no locations in the database"""
|
||||||
|
|
||||||
|
|
||||||
|
class FuckyWucky:
|
||||||
|
"""You made one."""
|
||||||
|
|
||||||
|
|
||||||
|
class EmptryString(DataBaseError):
|
||||||
|
"""Empty string provided"""
|
||||||
|
|
||||||
|
|
||||||
|
class CommandNotFound(DataBaseError):
|
||||||
|
"""Command not found"""
|
|
@ -0,0 +1,29 @@
|
||||||
|
from itertools import zip_longest
|
||||||
|
|
||||||
|
|
||||||
|
def get_name(args):
|
||||||
|
if len(args) > 0:
|
||||||
|
name = ' '.join(args)
|
||||||
|
else:
|
||||||
|
name = None
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def get_nickname(discord_user, special_users):
|
||||||
|
if discord_user.nick is None:
|
||||||
|
name = discord_user.display_name
|
||||||
|
else:
|
||||||
|
name = discord_user.nick
|
||||||
|
|
||||||
|
if name in special_users:
|
||||||
|
return special_users[name]
|
||||||
|
else:
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def get_args_dict(args):
|
||||||
|
if len(args) != 0:
|
||||||
|
return dict(zip_longest(*[iter(args)] * 2, fillvalue=" "))
|
||||||
|
else:
|
||||||
|
return {}
|
|
@ -0,0 +1,36 @@
|
||||||
|
from simplejson.errors import JSONDecodeError
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from GeoffreyApp.api.bot.BotErrors import UsernameLookupFailed
|
||||||
|
|
||||||
|
uuid_lookup_url = 'https://api.mojang.com/users/profiles/minecraft/{}'
|
||||||
|
username_lookup_url = 'https://api.mojang.com/user/profiles/{}/names'
|
||||||
|
|
||||||
|
|
||||||
|
def grab_json(url):
|
||||||
|
try:
|
||||||
|
json = requests.get(url).json()
|
||||||
|
if 'error' in json:
|
||||||
|
raise UsernameLookupFailed
|
||||||
|
|
||||||
|
except JSONDecodeError:
|
||||||
|
raise UsernameLookupFailed
|
||||||
|
|
||||||
|
return json
|
||||||
|
|
||||||
|
|
||||||
|
def grab_UUID(username):
|
||||||
|
player_data = grab_json(uuid_lookup_url.format(username))
|
||||||
|
return player_data['id']
|
||||||
|
|
||||||
|
|
||||||
|
def grab_playername(uuid):
|
||||||
|
player_data = grab_json(username_lookup_url.format(uuid))
|
||||||
|
|
||||||
|
if len(player_data) == 0:
|
||||||
|
raise UsernameLookupFailed
|
||||||
|
else:
|
||||||
|
last_index = len(player_data) - 1
|
||||||
|
|
||||||
|
return player_data[last_index]['name']
|
|
@ -0,0 +1,167 @@
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from discord import Game
|
||||||
|
from discord.ext import commands
|
||||||
|
from discord.utils import oauth_url
|
||||||
|
import logging.handlers as handlers
|
||||||
|
from sys import stdout
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
from GeoffreyApp.api.bot.BotErrors import *
|
||||||
|
from GeoffreyApp.api.commands import *
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
description = '''
|
||||||
|
Geoffrey (pronounced JOFF-ree) started his life as an inside joke none of you will understand.
|
||||||
|
At some point, she was to become an airhorn bot. Now, they know where your stuff is.
|
||||||
|
|
||||||
|
Please respect Geoffrey, the bot is very sensitive.
|
||||||
|
|
||||||
|
All commands must be prefaced with '?'
|
||||||
|
|
||||||
|
If have a suggestion or if something is borked, you can PM my ding dong of a creator BirbHD.
|
||||||
|
|
||||||
|
*You must use ?register before adding things to Geoffrey*
|
||||||
|
|
||||||
|
For a better a explanation on how this bot works go the following link:
|
||||||
|
https://github.com/joeyahines/Geoffrey/blob/master/README.md
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
bad_error_message = 'OOPSIE WOOPSIE!! Uwu We made a fucky wucky!! A wittle fucko boingo! The admins at our ' \
|
||||||
|
'headquarters are working VEWY HAWD to fix this! (Error in command {})'
|
||||||
|
|
||||||
|
extensions = []
|
||||||
|
'''
|
||||||
|
extensions = ['GeoffreyApp.cogs.Add_Commands',
|
||||||
|
'GeoffreyApp.cogs.Delete_Commands',
|
||||||
|
'GeoffreyApp.cogs.Edit_Commands',
|
||||||
|
'GeoffreyApp.cogs.Search_Commands',
|
||||||
|
'GeoffreyApp.cogs.Admin_Commands']
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class GeoffreyBot(commands.Bot):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(command_prefix=getattr(settings, 'BOT_PREFIX', '?'), description=description, pm_help=True, case_insensitive=True)
|
||||||
|
self.error_users = getattr(settings, 'ERROR_USERS', [])
|
||||||
|
self.admin_users = getattr(settings, 'MOD_RANK', [])
|
||||||
|
self.special_users = getattr(settings, 'SPECIAL_USERS', [])
|
||||||
|
self.default_status = getattr(settings, 'DEFAULT_STATUS', 'sed')
|
||||||
|
|
||||||
|
for extension in extensions:
|
||||||
|
try:
|
||||||
|
self.load_extension(extension)
|
||||||
|
except Exception as e:
|
||||||
|
logger.info('Failed to load extension {}'.format(extension))
|
||||||
|
raise e
|
||||||
|
|
||||||
|
async def on_ready(self):
|
||||||
|
logger.info("%s Online, ID: %s", self.user.name, self.user.id)
|
||||||
|
info = await self.application_info()
|
||||||
|
url = oauth_url(info.id)
|
||||||
|
logger.info("Bot url: %s", url)
|
||||||
|
await self.change_presence(activity=Game(self.default_status))
|
||||||
|
|
||||||
|
async def on_command(self, ctx):
|
||||||
|
if ctx.invoked_subcommand is None:
|
||||||
|
subcommand = ""
|
||||||
|
else:
|
||||||
|
subcommand = ":" + ctx.invoked_subcommand.__str__()
|
||||||
|
|
||||||
|
logger.info("User %s, used command %s%s with context: %s", ctx.message.author, ctx.command.name, subcommand,
|
||||||
|
ctx.args)
|
||||||
|
|
||||||
|
if ctx.invoked_with.lower() == 'help' and ctx.message.guild is not None:
|
||||||
|
await ctx.send("{}, I sent you some help in the DMs.".format(ctx.message.author.mention))
|
||||||
|
|
||||||
|
async def on_command_error(self, ctx, error):
|
||||||
|
error_str = ''
|
||||||
|
if hasattr(ctx, 'cog'):
|
||||||
|
if "Admin_Commands" in ctx.cog.__str__():
|
||||||
|
return
|
||||||
|
if hasattr(error, 'original'):
|
||||||
|
if isinstance(error.original, NoPermissionError):
|
||||||
|
error_str = 'You don\'t have permission for that cool command.'
|
||||||
|
elif isinstance(error.original, UsernameLookupFailed):
|
||||||
|
error_str = 'Your user name was not found, either Mojang is having a fucky wucky ' \
|
||||||
|
'or your nickname is not set correctly. *stares at the Mods*'
|
||||||
|
elif isinstance(error.original, PlayerNotFound):
|
||||||
|
error_str = 'Make sure to use ?register first you ding dong.'
|
||||||
|
elif isinstance(error.original, EntryNameNotUniqueError):
|
||||||
|
error_str = 'An entry in the database already has that name you ding dong.'
|
||||||
|
elif isinstance(error.original, DatabaseValueError):
|
||||||
|
error_str = 'Use a shorter name or a smaller value, dong ding.'
|
||||||
|
elif isinstance(error.original, NotOnServerError):
|
||||||
|
error_str = 'Command needs to be run on 24CC. Run this command there whoever you are.'.format()
|
||||||
|
elif isinstance(error.original, EmptryString):
|
||||||
|
error_str = 'Do not not pass empty string to Geoffrey. Ding dong.'
|
||||||
|
elif isinstance(error, commands.CommandOnCooldown):
|
||||||
|
return
|
||||||
|
elif isinstance(error, commands.UserInputError):
|
||||||
|
error_str = 'Invalid syntax for **{}** you ding dong:' \
|
||||||
|
.format(ctx.invoked_with, ctx.invoked_with)
|
||||||
|
|
||||||
|
pages = await self.formatter.format_help_for(ctx, ctx.command)
|
||||||
|
for page in pages:
|
||||||
|
error_str = error_str + '\n' + page
|
||||||
|
elif isinstance(error, commands.CommandNotFound):
|
||||||
|
return
|
||||||
|
|
||||||
|
if error_str is '':
|
||||||
|
await self.send_error_message(
|
||||||
|
'Geoffrey encountered unhandled exception: {} Command: **{}** Context: {}'.format(error,
|
||||||
|
ctx.command.name,
|
||||||
|
ctx.args))
|
||||||
|
error_str = bad_error_message.format(ctx.invoked_with)
|
||||||
|
|
||||||
|
logger.error("Geoffrey encountered exception: %s", error)
|
||||||
|
|
||||||
|
await ctx.message.channel.send('{} **Error Running Command:** {}'.format(
|
||||||
|
ctx.message.author.mention, error_str))
|
||||||
|
|
||||||
|
async def send_error_message(self, msg):
|
||||||
|
for user_id in self.error_users:
|
||||||
|
user = await self.get_user_info(user_id)
|
||||||
|
await user.send(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_logging():
|
||||||
|
discord_logger = logging.getLogger('discord')
|
||||||
|
discord_logger.setLevel(logging.INFO)
|
||||||
|
bot_info_logger = logging.getLogger('GeoffreyApp.api.bot.bot')
|
||||||
|
bot_info_logger.setLevel(logging.INFO)
|
||||||
|
console = logging.StreamHandler(stdout)
|
||||||
|
console.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
|
||||||
|
|
||||||
|
bot_info_logger.addHandler(console)
|
||||||
|
|
||||||
|
|
||||||
|
def start_bot():
|
||||||
|
bot = None
|
||||||
|
try:
|
||||||
|
bot = GeoffreyBot()
|
||||||
|
|
||||||
|
@bot.command(pass_context=True)
|
||||||
|
async def test(ctx):
|
||||||
|
"""
|
||||||
|
Checks if the bot is alive.
|
||||||
|
"""
|
||||||
|
await ctx.send('I\'m here you ding dong')
|
||||||
|
|
||||||
|
setup_logging()
|
||||||
|
|
||||||
|
bot.run(getattr(settings, 'DISCORD_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:
|
||||||
|
if bot is not None:
|
||||||
|
bot.loop.stop()
|
||||||
|
logger.info("Bot shutting down...")
|
|
@ -0,0 +1,146 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from geoffrey.BotErrors import *
|
||||||
|
from geoffrey.DiscordHelperFunctions import *
|
||||||
|
|
||||||
|
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
class Add_Commands:
|
||||||
|
"""
|
||||||
|
Commands for adding things to Geoffrey.
|
||||||
|
*You must use ?register before using any of these commands!*
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def register(self, ctx):
|
||||||
|
"""
|
||||||
|
Registers your Discord and Minecraft account with the the database
|
||||||
|
You must do this before adding entries to the database.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
player_name = get_nickname(ctx.message.author, self.bot.special_users)
|
||||||
|
self.bot.bot_commands.register(player_name, ctx.message.author.id)
|
||||||
|
await ctx.send('{}, you have been added to the database. Use ?help to see all the commands this bot can do.'
|
||||||
|
.format(ctx.message.author.mention))
|
||||||
|
except AttributeError:
|
||||||
|
raise NotOnServerError
|
||||||
|
except PlayerInDBError:
|
||||||
|
await ctx.send('{}, you are already in the database. Ding dong.'.format(ctx.message.author.mention))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def add_base(self, ctx, x_pos: int, z_pos: int, *args):
|
||||||
|
"""
|
||||||
|
Adds your base to the database. The base name is optional if this is your first base
|
||||||
|
?add_base [X Coordinate] [Z Coordinate] [Base Name]
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = get_name(args)
|
||||||
|
|
||||||
|
try:
|
||||||
|
base = self.bot.bot_commands.add_base(x_pos, z_pos, base_name=name, discord_uuid=ctx.message.author.id)
|
||||||
|
await ctx.send(
|
||||||
|
'{}, your base has been added to the database: \n\n{}'.format(ctx.message.author.mention, base))
|
||||||
|
except LocationInitError:
|
||||||
|
raise commands.UserInputError
|
||||||
|
except EntryNameNotUniqueError:
|
||||||
|
if name is None:
|
||||||
|
await ctx.send('{}, you already have one base in the database, you need to specify a base'
|
||||||
|
' name'.format(ctx.message.author.mention))
|
||||||
|
else:
|
||||||
|
await ctx.send(
|
||||||
|
'{}, a base called **{}** already exists. You need to specify a different name.'.format(
|
||||||
|
ctx.message.author.mention, name))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def add_shop(self, ctx, x_pos: int, z_pos: int, *args):
|
||||||
|
"""
|
||||||
|
Adds your shop to the database. The name is optional if this is your first shop
|
||||||
|
?add_shop [X Coordinate] [Z Coordinate] [Shop Name]
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = get_name(args)
|
||||||
|
|
||||||
|
try:
|
||||||
|
shop = self.bot.bot_commands.add_shop(x_pos, z_pos, shop_name=name, discord_uuid=ctx.message.author.id)
|
||||||
|
await ctx.send(
|
||||||
|
'{}, your shop has been added to the database: \n\n{}'.format(ctx.message.author.mention, shop))
|
||||||
|
except LocationInitError:
|
||||||
|
raise commands.UserInputError
|
||||||
|
except EntryNameNotUniqueError:
|
||||||
|
if name is None:
|
||||||
|
await ctx.send(
|
||||||
|
'{}, you already have one shop in the database, you need to specify a shop name'.format(
|
||||||
|
ctx.message.author.mention))
|
||||||
|
else:
|
||||||
|
await ctx.send(
|
||||||
|
'{}, a shop called **{}** already exists. You need to specify a different name.'.format(
|
||||||
|
ctx.message.author.mention, name))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def add_tunnel(self, ctx, tunnel_direction: str, tunnel_number: int, *args):
|
||||||
|
"""
|
||||||
|
Adds your tunnel to the database. If you only have one location, you do not need to specify a location name
|
||||||
|
|
||||||
|
Directions: North South East West
|
||||||
|
?tunnel [Tunnel Direction] [Tunnel Number] [Location Name]
|
||||||
|
"""
|
||||||
|
|
||||||
|
loc_name = get_name(args)
|
||||||
|
try:
|
||||||
|
self.bot.bot_commands.add_tunnel(tunnel_direction, tunnel_number, discord_uuid=ctx.message.author.id,
|
||||||
|
location_name=loc_name)
|
||||||
|
await ctx.send('{}, your tunnel has been added to the database'.format(ctx.message.author.mention))
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send('{}, you do not have a location called **{}**.'.format(
|
||||||
|
ctx.message.author.mention, loc_name))
|
||||||
|
except NoLocationsInDatabase:
|
||||||
|
await ctx.send('{}, you do not have a location in the database.'.format(
|
||||||
|
ctx.message.author.mention, loc_name))
|
||||||
|
except LocationHasTunnelError:
|
||||||
|
await ctx.send('{}, **{}** already has a tunnel.'.format(ctx.message.author.mention, loc_name))
|
||||||
|
except TunnelInitError:
|
||||||
|
await ctx.send('{}, invalid tunnel direction.'.format(ctx.message.author.mention))
|
||||||
|
except EntryNameNotUniqueError:
|
||||||
|
await ctx.send('{}, you have more than one location, you need to specify a location.'
|
||||||
|
.format(ctx.message.author.mention))
|
||||||
|
except InvalidTunnelError:
|
||||||
|
await ctx.send(
|
||||||
|
'{}, **{}** is an invalid tunnel direction.'.format(ctx.message.author.mention, tunnel_direction))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def add_item(self, ctx, item_name: str, quantity: int, diamond_price: int, *args):
|
||||||
|
"""
|
||||||
|
Adds an item to a shop's inventory. If you have one shop, the shop name is not required
|
||||||
|
|
||||||
|
Quantity for Diamond Price. eg. 32 Dirt for 1D. If the item name has spaces in wrap in in quotes eg "Silk Touch"
|
||||||
|
?add_item [Item Name] [Quantity] [Price] [Shop name]
|
||||||
|
"""
|
||||||
|
shop_name = get_name(args)
|
||||||
|
try:
|
||||||
|
self.bot.bot_commands.add_item(item_name, quantity, diamond_price, shop_name=shop_name,
|
||||||
|
discord_uuid=ctx.message.author.id)
|
||||||
|
await ctx.send(
|
||||||
|
'{}, **{}** has been added to the inventory of your shop.'.format(ctx.message.author.mention,
|
||||||
|
item_name))
|
||||||
|
except NoLocationsInDatabase:
|
||||||
|
await ctx.send('{}, you don\'t have any shops in the database.'.format(ctx.message.author.mention))
|
||||||
|
except EntryNameNotUniqueError:
|
||||||
|
await ctx.send('{}, you have more than one shop in the database, please specify a shop name.'
|
||||||
|
.format(ctx.message.author.mention))
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send(
|
||||||
|
'{}, you don\'t have any shops named **{}** in the database.'.format(ctx.message.author.mention,
|
||||||
|
shop_name))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Add_Commands(bot))
|
|
@ -0,0 +1,166 @@
|
||||||
|
from discord import Game
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from geoffrey.BotErrors import *
|
||||||
|
from geoffrey.DiscordHelperFunctions import get_name
|
||||||
|
|
||||||
|
|
||||||
|
def check_mod(user, admin_users):
|
||||||
|
try:
|
||||||
|
for role in user.roles:
|
||||||
|
if str(role.id) in admin_users:
|
||||||
|
return True
|
||||||
|
except AttributeError:
|
||||||
|
raise NotOnServerError
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class Admin_Commands:
|
||||||
|
"""
|
||||||
|
Commands for cool people only.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
async def error(self, ctx, error):
|
||||||
|
error_str = ""
|
||||||
|
|
||||||
|
if hasattr(error, "original"):
|
||||||
|
if isinstance(error.original, PlayerNotFound):
|
||||||
|
error_str = 'that player is not in the database.'
|
||||||
|
elif isinstance(error.original, DeleteEntryError) or isinstance(error.original, LocationLookUpError):
|
||||||
|
error_str = 'that player does not have a location by that name.'
|
||||||
|
|
||||||
|
if error_str is "":
|
||||||
|
error_str = 'the bot encountered the following error: {}'.format(error.__str__())
|
||||||
|
|
||||||
|
await ctx.send('{}, {}'.format(ctx.message.author.mention, error_str))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
async def test(self, ctx):
|
||||||
|
"""
|
||||||
|
Checks if the bot is alive.
|
||||||
|
"""
|
||||||
|
if check_mod(ctx.message.author, self.bot.admin_users):
|
||||||
|
await ctx.send('I\'m here you ding dong')
|
||||||
|
else:
|
||||||
|
raise NoPermissionError
|
||||||
|
|
||||||
|
@commands.group(pass_context=True)
|
||||||
|
async def mod(self, ctx):
|
||||||
|
"""
|
||||||
|
Bot moderation tools.
|
||||||
|
"""
|
||||||
|
if check_mod(ctx.message.author, self.bot.admin_users):
|
||||||
|
if ctx.invoked_subcommand is None:
|
||||||
|
await ctx.send('{}, invalid sub-command for command **mod**.'.format(ctx.message.author.mention))
|
||||||
|
else:
|
||||||
|
raise NoPermissionError
|
||||||
|
|
||||||
|
@mod.command(pass_context=True)
|
||||||
|
async def delete(self, ctx, discord_uuid: str, location_name: str):
|
||||||
|
"""
|
||||||
|
Deletes a location in the database.
|
||||||
|
"""
|
||||||
|
self.bot.bot_commands.delete(location_name, discord_uuid=discord_uuid)
|
||||||
|
await ctx.send('{}, **{}** has been deleted.'.format(ctx.message.author.mention, location_name))
|
||||||
|
|
||||||
|
@delete.error
|
||||||
|
async def delete_error(self, ctx, error):
|
||||||
|
await self.error(ctx, error)
|
||||||
|
|
||||||
|
@mod.command(pass_context=True)
|
||||||
|
async def edit_name(self, ctx, discord_uuid: str, new_name: str, current_name: str):
|
||||||
|
"""
|
||||||
|
Edits the name of a location in the database.
|
||||||
|
"""
|
||||||
|
self.bot.bot_commands.edit_name(new_name, current_name, discord_uuid=discord_uuid)
|
||||||
|
await ctx.send('{}, **{}** has been rename to **{}**.'.format(ctx.message.author.mention, current_name,
|
||||||
|
new_name))
|
||||||
|
|
||||||
|
@edit_name.error
|
||||||
|
async def edit_error(self, ctx, error):
|
||||||
|
await self.error(ctx, error)
|
||||||
|
|
||||||
|
@mod.command(pass_context=True)
|
||||||
|
async def update_mc_uuid(self, ctx, discord_uuid: str, mc_uuid: str):
|
||||||
|
"""
|
||||||
|
Updates a user's MC UUID
|
||||||
|
"""
|
||||||
|
self.bot.bot_commands.update_mc_uuid(discord_uuid, mc_uuid)
|
||||||
|
await ctx.send('{}, **{}** has been updated.'.format(ctx.message.author.mention, discord_uuid))
|
||||||
|
|
||||||
|
@update_mc_uuid.error
|
||||||
|
async def update_mc_uuid_error(self, ctx, error):
|
||||||
|
await self.error(ctx, error)
|
||||||
|
|
||||||
|
@mod.command(pass_context=True)
|
||||||
|
async def update_discord_uuid(self, ctx, new_discord_uuid: str, current_discord_uuid: str):
|
||||||
|
"""
|
||||||
|
Updates a user's Discord UUID
|
||||||
|
"""
|
||||||
|
self.bot.bot_commands.update_mc_uuid(current_discord_uuid, new_discord_uuid)
|
||||||
|
await ctx.send('{}, user **{}** has been updated.'.format(ctx.message.author.mention, current_discord_uuid))
|
||||||
|
|
||||||
|
@update_discord_uuid.error
|
||||||
|
async def update_discord_uuid_error(self, ctx, error):
|
||||||
|
await self.error(ctx, error)
|
||||||
|
|
||||||
|
@mod.command(pass_context=True)
|
||||||
|
async def update_mc_name(self, ctx, discord_uuid: str):
|
||||||
|
"""
|
||||||
|
Updates a user's MC name to the current name on the MC UUID
|
||||||
|
"""
|
||||||
|
self.bot.bot_commands.update_mc_name(discord_uuid)
|
||||||
|
await ctx.send('{}, user **{}**\'s MC name has update.'.format(ctx.message.author.mention, discord_uuid))
|
||||||
|
|
||||||
|
@update_mc_name.error
|
||||||
|
async def update_mc_name_error(self, ctx, error):
|
||||||
|
await self.error(ctx, error)
|
||||||
|
|
||||||
|
@mod.command(pass_context=True)
|
||||||
|
async def status(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Updates "playing [game]" status of the bot
|
||||||
|
"""
|
||||||
|
status = get_name(args)
|
||||||
|
await self.bot.change_presence(activity=Game(status))
|
||||||
|
await ctx.send('{}, status has been changed'.format(ctx.message.author.mention))
|
||||||
|
|
||||||
|
@mod.command(pass_context=True)
|
||||||
|
async def add_player(self, ctx, discord_uuid: str, mc_name: str):
|
||||||
|
"""
|
||||||
|
Manually add a player to the database
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
db_id = self.bot.bot_commands.add_player(discord_uuid, mc_name)
|
||||||
|
await ctx.send('{}, user **{}** been added to the data base with id {}.'.format(ctx.message.author.mention,
|
||||||
|
mc_name, db_id))
|
||||||
|
except PlayerInDBError:
|
||||||
|
await ctx.send('{}, user **{}** is already in the database.'.format(ctx.message.author.mention, mc_name))
|
||||||
|
|
||||||
|
@add_player.error
|
||||||
|
async def add_player_error(self, ctx, error):
|
||||||
|
await self.error(ctx, error)
|
||||||
|
|
||||||
|
@mod.command(pass_context=True)
|
||||||
|
async def find_player(self, ctx, discord_uuid: str):
|
||||||
|
"""
|
||||||
|
Finds a player in the database
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
db_id, username, discord_uuid, minecraft_uuid = self.bot.bot_commands.find_player(discord_uuid)
|
||||||
|
await ctx.send('Username: {}, id: {}, Discord UUID: {}, Minecraft UUID: {}'
|
||||||
|
.format(username, db_id, discord_uuid, minecraft_uuid))
|
||||||
|
except PlayerNotFound:
|
||||||
|
await ctx.send('That player is not in the database...')
|
||||||
|
|
||||||
|
@find_player.error
|
||||||
|
async def find_player_error(self, ctx, error):
|
||||||
|
await self.error(ctx, error)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Admin_Commands(bot))
|
|
@ -0,0 +1,65 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from geoffrey.BotErrors import *
|
||||||
|
from geoffrey.DiscordHelperFunctions import *
|
||||||
|
|
||||||
|
|
||||||
|
class Delete_Commands:
|
||||||
|
"""
|
||||||
|
Commands to help Geoffrey forget.
|
||||||
|
|
||||||
|
*You must use ?register before using any of these commands!*
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
async def delete(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Deletes a location from the database
|
||||||
|
|
||||||
|
?delete [Location name]
|
||||||
|
"""
|
||||||
|
loc = get_name(args)
|
||||||
|
try:
|
||||||
|
if loc is None:
|
||||||
|
raise commands.UserInputError
|
||||||
|
|
||||||
|
self.bot.bot_commands.delete(loc, discord_uuid=ctx.message.author.id)
|
||||||
|
await ctx.send(
|
||||||
|
'{}, your location named **{}** has been deleted.'.format(ctx.message.author.mention, loc))
|
||||||
|
except (DeleteEntryError, PlayerNotFound):
|
||||||
|
await ctx.send('{}, you do not have a location named **{}**.'.format(ctx.message.author.mention, loc))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
async def delete_item(self, ctx, item: str, *args):
|
||||||
|
"""
|
||||||
|
Deletes an item listing from a shop inventory
|
||||||
|
|
||||||
|
The item name must be wrapped in quotes if it has a space in it
|
||||||
|
?delete_name [Item] [Shop Name]
|
||||||
|
"""
|
||||||
|
|
||||||
|
shop = get_name(args)
|
||||||
|
try:
|
||||||
|
shop_name = self.bot.bot_commands.delete_item(item, shop, discord_uuid=ctx.message.author.id)
|
||||||
|
|
||||||
|
await ctx.send('{}, **{}** has been removed from the inventory of **{}**.'.
|
||||||
|
format(ctx.message.author.mention, item, shop_name))
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send('{}, you do not have a shop called **{}**.'.format(ctx.message.author.mention, shop))
|
||||||
|
except NoLocationsInDatabase:
|
||||||
|
await ctx.send('{}, you do have any shops in the database.'.format(ctx.message.author.mention))
|
||||||
|
except EntryNameNotUniqueError:
|
||||||
|
await ctx.send('{}, you have more than one shop in the database, please specify a shop name.'
|
||||||
|
.format(ctx.message.author.mention))
|
||||||
|
except DeleteEntryError:
|
||||||
|
if shop is not None:
|
||||||
|
await ctx.send('{}, **{}** does not sell **{}**.'.format(ctx.message.author.mention, shop, item))
|
||||||
|
else:
|
||||||
|
await ctx.send('{}, your shop does not sell **{}**.'.format(ctx.message.author.mention, item))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Delete_Commands(bot))
|
|
@ -0,0 +1,76 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from geoffrey.BotErrors import *
|
||||||
|
from geoffrey.DiscordHelperFunctions import *
|
||||||
|
|
||||||
|
|
||||||
|
class Edit_Commands:
|
||||||
|
"""
|
||||||
|
Commands for editing your stuff in Geoffrey.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def edit_pos(self, ctx, x_pos: int, z_pos: int, *args):
|
||||||
|
"""
|
||||||
|
Edits the position of a location
|
||||||
|
|
||||||
|
?edit_pos [X Coordinate] [Z Coordinate] [Location Name]
|
||||||
|
"""
|
||||||
|
loc = get_name(args)
|
||||||
|
try:
|
||||||
|
loc_str = self.bot.bot_commands.edit_pos(x_pos, z_pos, loc, discord_uuid=ctx.message.author.id)
|
||||||
|
|
||||||
|
await ctx.send(
|
||||||
|
'{}, the following location has been updated: \n\n{}'.format(ctx.message.author.mention, loc_str))
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send('{}, you do not have a location called **{}**.'.format(
|
||||||
|
ctx.message.author.mention, loc))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def edit_tunnel(self, ctx, tunnel_direction: str, tunnel_number: int, *args):
|
||||||
|
"""
|
||||||
|
Edits the tunnel of a location
|
||||||
|
|
||||||
|
Directions: North South East West
|
||||||
|
?edit_tunnel [Tunnel Direction] [Tunnel Number] [Location Name]
|
||||||
|
"""
|
||||||
|
loc = get_name(args)
|
||||||
|
try:
|
||||||
|
loc_str = self.bot.bot_commands.edit_tunnel(tunnel_direction, tunnel_number, loc,
|
||||||
|
discord_uuid=ctx.message.author.id)
|
||||||
|
|
||||||
|
await ctx.send(
|
||||||
|
'{}, the following location has been updated: \n\n{}'.format(ctx.message.author.mention, loc_str))
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send('{}, you do not have a location called **{}**.'.format(
|
||||||
|
ctx.message.author.mention, loc))
|
||||||
|
except InvalidTunnelError:
|
||||||
|
await ctx.send(
|
||||||
|
'{}, **{}** is an invalid tunnel direction.'.format(ctx.message.author.mention, tunnel_direction))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def edit_name(self, ctx, new_name: str, current_name: str):
|
||||||
|
"""
|
||||||
|
Edits the name of a location
|
||||||
|
|
||||||
|
IF A NAME HAS SPACES IN IT YOU NEED TO WRAP IT IN QUOTATION MARKS. eg. "Cool Shop 123"
|
||||||
|
?edit_name [New Name] [Current Name]
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
loc_str = self.bot.bot_commands.edit_name(new_name, current_name, discord_uuid=ctx.message.author.id)
|
||||||
|
|
||||||
|
await ctx.send(
|
||||||
|
'{}, the following location has been updated: \n\n{}'.format(ctx.message.author.mention, loc_str))
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send('{}, you do not have a location called **{}**.'.format(
|
||||||
|
ctx.message.author.mention, current_name))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Edit_Commands(bot))
|
|
@ -0,0 +1,139 @@
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from geoffrey.BotErrors import *
|
||||||
|
from geoffrey.DiscordHelperFunctions import *
|
||||||
|
|
||||||
|
|
||||||
|
class Search_Commands:
|
||||||
|
"""
|
||||||
|
Commands to find stuff.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def find(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Finds all the locations matching the search term
|
||||||
|
?find [Search]
|
||||||
|
"""
|
||||||
|
search = get_name(args)
|
||||||
|
try:
|
||||||
|
|
||||||
|
if search is None:
|
||||||
|
raise commands.UserInputError
|
||||||
|
|
||||||
|
result = self.bot.bot_commands.find(search)
|
||||||
|
|
||||||
|
await ctx.send(
|
||||||
|
'{}, The following entries match **{}**:\n{}'.format(ctx.message.author.mention, search, result))
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send(
|
||||||
|
'{}, no matches to **{}** were found in the database.'.format(ctx.message.author.mention, search))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def tunnel(self, ctx, player: str):
|
||||||
|
"""
|
||||||
|
Finds all the tunnels a player owns
|
||||||
|
?tunnel [Player]
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
result = self.bot.bot_commands.tunnel(player)
|
||||||
|
|
||||||
|
await ctx.send(
|
||||||
|
'{}, **{}** owns the following tunnel(s): \n{}'.format(ctx.message.author.mention, player, result))
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send('{}, no tunnels for **{}** were found in the database.'
|
||||||
|
.format(ctx.message.author.mention, player))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def find_around(self, ctx, x_pos: int, z_pos: int, *args):
|
||||||
|
"""
|
||||||
|
Finds all the locations around a certain point.
|
||||||
|
The radius defaults to 200 blocks if no value is given
|
||||||
|
|
||||||
|
Default dimension is the overworld
|
||||||
|
?find_around [X Coordinate] [Z Coordinate] [Radius]
|
||||||
|
"""
|
||||||
|
radius = 200
|
||||||
|
dimension = 'Overworld'
|
||||||
|
|
||||||
|
try:
|
||||||
|
if len(args) > 0:
|
||||||
|
radius = int(args[0])
|
||||||
|
|
||||||
|
base_string = self.bot.bot_commands.find_around(x_pos, z_pos, radius, dimension)
|
||||||
|
|
||||||
|
if len(base_string) != 0:
|
||||||
|
await ctx.send('{}, the following locations(s) are within **{}** blocks of that point: \n {}'.format(
|
||||||
|
ctx.message.author.mention, radius, base_string))
|
||||||
|
else:
|
||||||
|
await ctx.send('{}, there are no locations within {} blocks of that point'
|
||||||
|
.format(ctx.message.author.mention, radius))
|
||||||
|
except ValueError:
|
||||||
|
await ctx.send(
|
||||||
|
'{}, invalid radius, the radius must be a whole number.'.format(ctx.message.author.mention,
|
||||||
|
radius))
|
||||||
|
except InvalidDimError:
|
||||||
|
await ctx.send('{}, {} is an invalid dimension.'.format(ctx.message.author.mention, dimension))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def selling(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Lists all the shops selling an item
|
||||||
|
|
||||||
|
?selling [item]
|
||||||
|
"""
|
||||||
|
item_name = get_name(args)
|
||||||
|
|
||||||
|
if item_name is None:
|
||||||
|
raise commands.UserInputError
|
||||||
|
try:
|
||||||
|
|
||||||
|
result = self.bot.bot_commands.selling(item_name)
|
||||||
|
await ctx.send(
|
||||||
|
'{}, the following shop(s) sell **{}**: \n{}'.format(ctx.message.author.mention, item_name, result))
|
||||||
|
except ItemNotFound:
|
||||||
|
await ctx.send('{}, no shop sells **{}**.'.format(ctx.message.author.mention, item_name))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def info(self, ctx, *args):
|
||||||
|
"""
|
||||||
|
Displays info about a location.
|
||||||
|
|
||||||
|
If the location is a shop, it displays the shop's inventory
|
||||||
|
?info [Location Name]
|
||||||
|
"""
|
||||||
|
loc = get_name(args)
|
||||||
|
try:
|
||||||
|
|
||||||
|
if loc is None:
|
||||||
|
raise commands.UserInputError
|
||||||
|
|
||||||
|
info_str = self.bot.bot_commands.info(loc)
|
||||||
|
await ctx.send(info_str)
|
||||||
|
except LocationLookUpError:
|
||||||
|
await ctx.send('{}, no locations in the database match **{}**.'.format(ctx.message.author.mention, loc))
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
@commands.cooldown(5, 60, commands.BucketType.user)
|
||||||
|
async def me(self, ctx):
|
||||||
|
"""
|
||||||
|
Displays all your locations in the database
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
loc_str = self.bot.bot_commands.me(discord_uuid=ctx.message.author.id)
|
||||||
|
await ctx.send('{}, here are your location(s) in the database: \n {}'.format(ctx.message.author.mention,
|
||||||
|
loc_str))
|
||||||
|
except PlayerNotFound:
|
||||||
|
await ctx.send('{}, you don\'t have any locations in the database.'.format(ctx.message.author.mention))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Search_Commands(bot))
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
from GeoffreyApp.api.bot.BotErrors import *
|
||||||
|
from django.db.models import Q, F
|
||||||
|
from GeoffreyApp.models import *
|
||||||
|
from GeoffreyApp.api.bot.MinecraftAccountInfoGrabber import *
|
||||||
|
|
||||||
|
post_list = []
|
||||||
|
get_list = []
|
||||||
|
delete_list = []
|
||||||
|
|
||||||
|
|
||||||
|
def post(func):
|
||||||
|
def command():
|
||||||
|
post_list.append(func)
|
||||||
|
|
||||||
|
return command()
|
||||||
|
|
||||||
|
|
||||||
|
def delete(func):
|
||||||
|
def command():
|
||||||
|
delete_list.append(func)
|
||||||
|
|
||||||
|
return command()
|
||||||
|
|
||||||
|
|
||||||
|
def get(func):
|
||||||
|
def command():
|
||||||
|
get_list.append(func)
|
||||||
|
|
||||||
|
return command()
|
||||||
|
|
||||||
|
|
||||||
|
def get_player(discord_uuid=None, mc_uuid=None):
|
||||||
|
if discord_uuid is not None:
|
||||||
|
player = Player.objects.get(discord_uuid=discord_uuid)
|
||||||
|
elif mc_uuid is not None:
|
||||||
|
player = Player.objects.get(mc_uuid=discord_uuid)
|
||||||
|
else:
|
||||||
|
raise AttributeError
|
||||||
|
|
||||||
|
return player
|
||||||
|
|
||||||
|
|
||||||
|
def get_location(owner, name=None, loc_type=Location):
|
||||||
|
if name is None:
|
||||||
|
loc_list = Location.objects.all().select_related(loc_type.__name__).get(owner=owner)
|
||||||
|
if len(loc_list) == 1:
|
||||||
|
loc = loc_list[0]
|
||||||
|
elif len(loc_list) == 0:
|
||||||
|
raise NoLocationsInDatabase
|
||||||
|
else:
|
||||||
|
raise EntryNameNotUniqueError
|
||||||
|
else:
|
||||||
|
loc_list = Location.objects.all().select_related(loc_type.__name__).get(owner=owner, name=name)
|
||||||
|
if len(loc_list) == 1:
|
||||||
|
loc = loc_list[0]
|
||||||
|
else:
|
||||||
|
raise LocationLookUpError
|
||||||
|
|
||||||
|
return loc
|
||||||
|
|
||||||
|
|
||||||
|
@post
|
||||||
|
def register(player_name, discord_uuid):
|
||||||
|
mc_uuid = grab_UUID(player_name)
|
||||||
|
player = Player.objects.create(name=player_name, mc_uuid=mc_uuid, discord_uuid=discord_uuid)
|
||||||
|
|
||||||
|
return player.json
|
||||||
|
|
||||||
|
|
||||||
|
@post
|
||||||
|
def add_location(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None, loc_type=Location):
|
||||||
|
player = get_player(discord_uuid, mc_uuid)
|
||||||
|
try:
|
||||||
|
get_location(player, name, loc_type=loc_type)
|
||||||
|
raise EntryNameNotUniqueError
|
||||||
|
except (NoLocationsInDatabase, LocationLookUpError):
|
||||||
|
if name is None:
|
||||||
|
name = "{}'s {}".format(player.name, loc_type.__name__)
|
||||||
|
|
||||||
|
if loc_type == Base:
|
||||||
|
location = Base.objects.create(owner=player, name=name, x_coord=x_pos, z_coord=z_pos)
|
||||||
|
elif loc_type == Shop:
|
||||||
|
location = Shop.objects.create(owner=player, name=name, x_coord=x_pos, z_coord=z_pos)
|
||||||
|
else:
|
||||||
|
raise DataBaseError
|
||||||
|
|
||||||
|
return location
|
||||||
|
|
||||||
|
|
||||||
|
@post
|
||||||
|
def add_tunnel(tunnel_direction, tunnel_number, location_name=None, discord_uuid=None, mc_uuid=None):
|
||||||
|
player = get_player(discord_uuid, mc_uuid)
|
||||||
|
if location_name is None:
|
||||||
|
loc = get_location(player, name=location_name)
|
||||||
|
location_name = loc.name
|
||||||
|
|
||||||
|
tunnel = Tunnel.objects.create(tunnel_direction, tunnel_number, Location=get_location(player, location_name))
|
||||||
|
|
||||||
|
return tunnel
|
||||||
|
|
||||||
|
|
||||||
|
@get
|
||||||
|
def find_location(search):
|
||||||
|
limit = 25
|
||||||
|
|
||||||
|
locations = Location.objects.filter(Q(name__icontains=search) | Q(owner__name__icontains=search))[:limit]
|
||||||
|
|
||||||
|
if len(locations) == 0:
|
||||||
|
raise LocationLookUpError
|
||||||
|
|
||||||
|
return locations
|
||||||
|
|
||||||
|
|
||||||
|
@delete
|
||||||
|
def delete(name, discord_uuid=None, mc_uuid=None):
|
||||||
|
owner = get_player(discord_uuid, mc_uuid)
|
||||||
|
Location.objects.get(name__iexact=name, owner=owner)
|
||||||
|
|
||||||
|
|
||||||
|
@get
|
||||||
|
def find_around(x_pos, z_pos, radius=200):
|
||||||
|
locations = Location.objects.get(x_coord__range=(x_pos - radius, x_pos + radius),
|
||||||
|
z_coord__range=(z_pos - radius, z_pos + radius), dimension='O')
|
||||||
|
|
||||||
|
return locations
|
||||||
|
|
||||||
|
|
||||||
|
@post
|
||||||
|
def add_item(item_name, quantity, diamond_price, shop_name=None, discord_uuid=None, mc_uuid=None):
|
||||||
|
player = get_player(discord_uuid, mc_uuid)
|
||||||
|
|
||||||
|
shop = get_location(player, shop_name, Shop)
|
||||||
|
|
||||||
|
item_listing = ItemListing.objects.create(shop=shop, quantity=quantity, price=diamond_price, item_name=item_name)
|
||||||
|
|
||||||
|
return item_listing
|
||||||
|
|
||||||
|
|
||||||
|
# TODO Re-implement selling shop search
|
||||||
|
@get
|
||||||
|
def selling(item_name):
|
||||||
|
if len(item_name) == 0:
|
||||||
|
raise EmptryString
|
||||||
|
|
||||||
|
items = ItemListing.objects.annotate(normalized_price=F('price') / F('amount')).filter(item_name__icontains=item_name).order_by('normalized_price')
|
||||||
|
|
||||||
|
if len(items) == 0:
|
||||||
|
raise ItemNotFound
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
@get
|
||||||
|
def info(location_name):
|
||||||
|
loc = Location.objects.get(name__iexact=location_name)
|
||||||
|
return loc
|
||||||
|
|
||||||
|
|
||||||
|
@get
|
||||||
|
def tunnel(player_name):
|
||||||
|
tunnels = Tunnel.objects.get(location__owner__name__icontains=player_name)
|
||||||
|
|
||||||
|
if len(tunnels) == 0:
|
||||||
|
raise LocationLookUpError
|
||||||
|
|
||||||
|
return tunnel
|
||||||
|
|
||||||
|
|
||||||
|
@post
|
||||||
|
def edit_pos(x, z, loc_name, discord_uuid=None, mc_uuid=None):
|
||||||
|
|
||||||
|
player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid)
|
||||||
|
location = get_location(player, loc_name)
|
||||||
|
|
||||||
|
location.x = x
|
||||||
|
location.z = z
|
||||||
|
location.save()
|
||||||
|
|
||||||
|
return location
|
||||||
|
|
||||||
|
|
||||||
|
@post
|
||||||
|
def edit_tunnel(tunnel_direction, tunnel_number, loc_name, discord_uuid=None, mc_uuid=None):
|
||||||
|
player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid)
|
||||||
|
location = get_location(player, loc_name)
|
||||||
|
|
||||||
|
if location.tunnel is not None:
|
||||||
|
location.tunnel.tunnel_direction = tunnel_direction
|
||||||
|
location.tunnel.tunnel_number = tunnel_number
|
||||||
|
else:
|
||||||
|
Tunnel.objects.create(tunnel_direction=tunnel_direction, tunnel_number=tunnel_number, location=location)
|
||||||
|
|
||||||
|
return location
|
||||||
|
|
||||||
|
|
||||||
|
@post
|
||||||
|
def edit_name(new_name, loc_name, discord_uuid=None, mc_uuid=None):
|
||||||
|
player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid)
|
||||||
|
location = get_location(player, loc_name)
|
||||||
|
|
||||||
|
location.name = new_name
|
||||||
|
location.save()
|
||||||
|
|
||||||
|
return location
|
||||||
|
|
||||||
|
|
||||||
|
@post
|
||||||
|
def delete_item(item, shop_name, discord_uuid=None, mc_uuid=None):
|
||||||
|
player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid)
|
||||||
|
|
||||||
|
shop = get_location(player, shop_name, Shop)
|
||||||
|
|
||||||
|
ItemListing.objects.filter(item_name__iexact=item, shop=shop).delete()
|
||||||
|
|
||||||
|
return shop
|
||||||
|
|
||||||
|
|
||||||
|
@get
|
||||||
|
def me(discord_uuid=None, mc_uuid=None):
|
||||||
|
player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid)
|
||||||
|
|
||||||
|
locations = Location.objects.get(owner=player)
|
||||||
|
|
||||||
|
if len(locations) == 0:
|
||||||
|
raise PlayerNotFound
|
||||||
|
|
||||||
|
return locations
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.conf.urls import url
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
import GeoffreyApp.api.views as api
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^command/(?P<command>\w{1,20})/$', csrf_exempt(api.CommandAPI.as_view()), name="api-command"),
|
||||||
|
]
|
|
@ -0,0 +1,36 @@
|
||||||
|
from django.views.generic import View
|
||||||
|
from django.http import JsonResponse
|
||||||
|
|
||||||
|
import GeoffreyApp.api.commands as commands
|
||||||
|
from GeoffreyApp.api.bot.BotErrors import *
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(request, command, command_list):
|
||||||
|
command = command.lower()
|
||||||
|
response = []
|
||||||
|
try:
|
||||||
|
for c in command_list:
|
||||||
|
if command == c.__name__:
|
||||||
|
ret = c(**request.dict())
|
||||||
|
response.append(ret)
|
||||||
|
return JsonResponse(response, safe=False)
|
||||||
|
|
||||||
|
raise CommandNotFound
|
||||||
|
except Exception as e:
|
||||||
|
response.append({"error": e.__class__.__name__})
|
||||||
|
|
||||||
|
return JsonResponse(response, safe=False)
|
||||||
|
|
||||||
|
|
||||||
|
class CommandAPI(View):
|
||||||
|
def get(self, request, command):
|
||||||
|
get = request.GET
|
||||||
|
return run_command(get, command, commands.get_list)
|
||||||
|
|
||||||
|
def post(self, request, command):
|
||||||
|
post = request.POST
|
||||||
|
return run_command(post, command, commands.post_list)
|
||||||
|
|
||||||
|
def delete(self, request, command):
|
||||||
|
delete = request.DELETE
|
||||||
|
return run_command(delete, command, commands.delete_list)
|
5
apps.py
5
apps.py
|
@ -1,5 +0,0 @@
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class GeoffreyConfig(AppConfig):
|
|
||||||
name = 'geoffrey'
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Geoffrey.settings")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import django
|
||||||
|
django.setup()
|
||||||
|
from GeoffreyApp.api.bot.bot import start_bot
|
||||||
|
|
||||||
|
start_bot()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,30 +51,30 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Base',
|
name='Base',
|
||||||
fields=[
|
fields=[
|
||||||
('location_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='geoffrey.Location')),
|
('location_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='GeoffreyApp.Location')),
|
||||||
],
|
],
|
||||||
bases=('geoffrey.location',),
|
bases=('GeoffreyApp.location',),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Shop',
|
name='Shop',
|
||||||
fields=[
|
fields=[
|
||||||
('location_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='geoffrey.Location')),
|
('location_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='GeoffreyApp.Location')),
|
||||||
],
|
],
|
||||||
bases=('geoffrey.location',),
|
bases=('GeoffreyApp.location',),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='tunnel',
|
model_name='tunnel',
|
||||||
name='location',
|
name='location',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tunnel_location', to='geoffrey.Location'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tunnel_location', to='GeoffreyApp.Location'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='location',
|
model_name='location',
|
||||||
name='owner',
|
name='owner',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owner_player', to='geoffrey.Player'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owner_player', to='GeoffreyApp.Player'),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='itemlisting',
|
model_name='itemlisting',
|
||||||
name='shop',
|
name='shop',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shop_selling', to='geoffrey.Shop'),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shop_selling', to='GeoffreyApp.Shop'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
24
models.py
24
models.py
|
@ -1,13 +1,17 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from sys import maxsize
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
|
|
||||||
class Player(models.Model):
|
class Player(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30, unique=True)
|
||||||
mc_uuid = models.CharField(max_length=36)
|
mc_uuid = models.CharField(max_length=36, unique=True)
|
||||||
discord_uuid = models.CharField(max_length=50)
|
discord_uuid = models.CharField(max_length=50, unique=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def json(self):
|
||||||
|
return {"Name": self.name, "MC UUID": self.mc_uuid, "Discord UUID": self.discord_uuid}
|
||||||
|
|
||||||
|
|
||||||
class Location(models.Model):
|
class Location(models.Model):
|
||||||
|
@ -25,6 +29,11 @@ class Location(models.Model):
|
||||||
|
|
||||||
owner = models.ForeignKey(Player, related_name='owner_player', on_delete=models.CASCADE)
|
owner = models.ForeignKey(Player, related_name='owner_player', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def json(self):
|
||||||
|
return {"Type": str(type(self)), "Name": self.name, "x_coord": self.x_coord, "z_coord": self.z_coord,
|
||||||
|
"dimension": self.dimension, "Owner": self.owner.json}
|
||||||
|
|
||||||
|
|
||||||
class Shop(Location):
|
class Shop(Location):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -43,6 +52,13 @@ class ItemListing(models.Model):
|
||||||
|
|
||||||
shop = models.ForeignKey(Shop, related_name="shop_selling", on_delete=models.CASCADE)
|
shop = models.ForeignKey(Shop, related_name="shop_selling", on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def normalized_price(self):
|
||||||
|
if self.amount == 0:
|
||||||
|
return maxsize
|
||||||
|
else:
|
||||||
|
return self.price/self.amount
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Item: %d %s for %d" % (self.amount, self.item_name, self.amount)
|
return "Item: %d %s for %d" % (self.amount, self.item_name, self.amount)
|
||||||
|
|
||||||
|
|
3
views.py
3
views.py
|
@ -1,6 +1,9 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
import subprocess, os
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
return HttpResponse("Geoffrey is here!")
|
return HttpResponse("Geoffrey is here!")
|
||||||
|
|
Loading…
Reference in New Issue