Added features and bug fixes according to sprint 1. Added new location info to locations and made getting shop info easier. Also fixed bugs that caused db crahses.

doc_update
Joey Hines 2018-07-03 19:05:35 -05:00
parent 1783c58e2a
commit 06f5feae4e
3 changed files with 99 additions and 38 deletions

View File

@ -30,11 +30,11 @@ class GeoffreyDatabase:
self.add_object(shop) self.add_object(shop)
return shop return shop
def add_item(self, player_name, shop_name, item_name, price): def add_item(self, player_name, shop_name, item_name, price, amount):
try: try:
shop = self.find_shop_by_name_and_owner(player_name, shop_name) shop = self.find_shop_by_name_and_owner(player_name, shop_name)
item = ItemListing(item_name, price, shop[0]) item = ItemListing(item_name, price, amount, shop[0])
self.add_object(item) self.add_object(item)
except IndexError: except IndexError:
raise LocationLookUpError raise LocationLookUpError
@ -65,11 +65,11 @@ class GeoffreyDatabase:
self.session.commit() self.session.commit()
def find_location_by_name(self, name): def find_location_by_name(self, name):
expr = Location.name.like('%{}%'.format(name)) expr = Location.name.ilike('%{}%'.format(name))
return self.query_by_filter(Location, expr) return self.query_by_filter(Location, expr)
def find_shop_by_name(self, name): def find_shop_by_name(self, name):
expr = Location.name.like('%{}%'.format(name)) expr = Location.name.ilike('%{}%'.format(name))
return self.query_by_filter(Shop, expr) return self.query_by_filter(Shop, expr)
def find_location_by_owner(self, owner_name): def find_location_by_owner(self, owner_name):
@ -79,22 +79,23 @@ class GeoffreyDatabase:
def find_shop_by_name_and_owner(self, owner_name, name): def find_shop_by_name_and_owner(self, owner_name, name):
player = self.find_player(owner_name) player = self.find_player(owner_name)
expr = (Shop.owner == player) & (Shop.name == name) expr = (Shop.owner == player) & (Shop.name.ilike(name))
return self.query_by_filter(Shop, expr) return self.query_by_filter(Shop, expr)
def find_location_by_name_and_owner(self, owner_name, name): def find_location_by_name_and_owner(self, owner_name, name):
player = self.find_player(owner_name) player = self.find_player(owner_name)
expr = (Location.owner == player) & (Location.name == name) expr = (Location.owner == player) & (Location.name.ilike(name))
return self.query_by_filter(Location, expr) return self.query_by_filter(Location, expr)
def find_location_around(self, x_pos, z_pos, radius): def find_location_around(self, x_pos, z_pos, radius):
radius = radius + 1 #gets a the correct area
expr = (Location.x < x_pos + radius) & (Location.x > x_pos - radius) & (Location.z < z_pos + radius) & \ expr = (Location.x < x_pos + radius) & (Location.x > x_pos - radius) & (Location.z < z_pos + radius) & \
(Location.z > z_pos - radius) (Location.z > z_pos - radius)
return self.query_by_filter(Location, expr) return self.query_by_filter(Location, expr)
def find_item(self, item_name): def find_item(self, item_name):
expr = ItemListing.name.like(item_name) expr = ItemListing.name.ilike('{}'.format(item_name))
return self.query_by_filter(ItemListing, expr) return self.query_by_filter(ItemListing, expr)
def find_shop_selling_item(self, item_name): def find_shop_selling_item(self, item_name):
@ -103,6 +104,7 @@ class GeoffreyDatabase:
shops = [] shops = []
for listing in listings: for listing in listings:
shops.append(listing.shop) shops.append(listing.shop)
shops.append(listing.__str__())
return shops return shops
@ -183,6 +185,38 @@ class TunnelDirection(enum.Enum):
raise ValueError raise ValueError
class TunnelSide(enum.Enum):
right = 'right'
left = 'left'
def str_to_tunnel_side(arg):
arg = arg.lower()
if arg == TunnelSide.right.value:
return TunnelSide.right
elif arg == TunnelSide.left.value:
return TunnelSide.left
else:
raise ValueError
class Dimension(enum.Enum):
overworld = 'overworld'
nether = 'nether'
end = 'end'
def str_to_dimension(arg):
arg = arg.lower()
if arg == Dimension.overworld.value:
return Dimension.overworld
elif arg == Dimension.nether.value:
return Dimension.nether
elif arg == Dimension.end.value:
return Dimension.end
else:
raise ValueError
class Player(SQL_Base): class Player(SQL_Base):
__tablename__ = 'Players' __tablename__ = 'Players'
@ -205,6 +239,9 @@ class Location(SQL_Base):
z = Column(Integer) z = Column(Integer)
tunnelNumber = Column(Integer) tunnelNumber = Column(Integer)
direction = Column(Enum(TunnelDirection)) direction = Column(Enum(TunnelDirection))
tunnel_side = Column(Enum(TunnelSide))
dimension = Column(Enum(Dimension))
owner_id = Column(Integer, ForeignKey('Players.id')) owner_id = Column(Integer, ForeignKey('Players.id'))
owner = relationship("Player", back_populates="locations") owner = relationship("Player", back_populates="locations")
type = Column(String) type = Column(String)
@ -225,15 +262,21 @@ class Location(SQL_Base):
if len(args) > 0: if len(args) > 0:
self.direction = TunnelDirection.str_to_tunnel_dir(args[0]) self.direction = TunnelDirection.str_to_tunnel_dir(args[0])
self.tunnelNumber = int(args[1]) self.tunnelNumber = int(args[1])
self.tunnel_side = TunnelSide.str_to_tunnel_side(args[2])
if len(args) > 3:
self.dimension = Dimension.str_to_dimension(args[3])
else:
self.dimension = Dimension.str_to_dimension("overworld")
except (ValueError, IndexError): except (ValueError, IndexError):
raise LocationInitError raise LocationInitError
def pos_to_str(self): def pos_to_str(self):
return '(x= {}, y= {}, z= {})'.format(self.x, self.y, self.z) return '(x= {}, y= {}, z= {}) in the {}'.format(self.x, self.y, self.z, self.dimension.value.title())
def nether_tunnel_addr_to_str(self): def nether_tunnel_addr_to_str(self):
return '{} {}'.format(self.direction.value.title(), self.tunnelNumber) return '{} {} {}'.format(self.direction.value.title(), self.tunnelNumber, self.tunnel_side.value.title())
def __str__(self): def __str__(self):
if self.direction is not None: if self.direction is not None:
@ -262,14 +305,16 @@ class ItemListing(SQL_Base):
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String) name = Column(String)
price = Column(Integer) price = Column(Integer)
amount = Column(Integer)
shop_id = Column(Integer, ForeignKey('Shops.shop_id')) shop_id = Column(Integer, ForeignKey('Shops.shop_id'))
shop = relationship("Shop", back_populates="inventory") shop = relationship("Shop", back_populates="inventory")
def __init__(self, name, price, shop): def __init__(self, name, price, amount, shop):
self.name = name self.name = name
self.price = price self.price = price
self.amount = amount
self.shop = shop self.shop = shop
def __str__(self): def __str__(self):
return "Item: {}, Price: {}D".format(self.name, self.price) return "Item: {}, Price: {} for {}D".format(self.name, self.amount, self.price)

View File

@ -3,6 +3,7 @@ from DatabaseModels import *
from BotErrors import * from BotErrors import *
from MinecraftAccountInfoGrabber import * from MinecraftAccountInfoGrabber import *
import configparser import configparser
import sqlite3
#from WebInterface import * #from WebInterface import *
TOKEN = '' TOKEN = ''
@ -38,6 +39,12 @@ async def on_command_error(error, ctx):
.format(ctx.invoked_with, ctx.invoked_with) .format(ctx.invoked_with, ctx.invoked_with)
elif isinstance(error.original, UsernameLookupFailed): elif isinstance(error.original, UsernameLookupFailed):
error_str = error.original.__doc__ error_str = error.original.__doc__
elif isinstance(error.original, OverflowError):
error_str = 'Wow buddy, that\'s a big number. Please don\'t do that.'
database.session.rollback()
elif isinstance(error.original, sqlite3.IntegrityError):
error_str = 'Off, the fuck did you do? Try the command again but be less of a ding dong with it.'
database.session.rollback()
else: else:
error_str = bad_error_message.format(ctx.invoked_with, error) error_str = bad_error_message.format(ctx.invoked_with, error)
@ -57,7 +64,8 @@ async def addbase(ctx, name: str, x_pos: int, y_pos: int, z_pos: int, * args):
''' '''
Add your base to the database. Add your base to the database.
The tunnel address is optional. The tunnel address is optional.
?addbase [Base Name] [X Coordinate] [Y Coordinate] [Z Coordinate] [Tunnel Color] [Tunnel Position] The default dimension is the overworld. Valid options: overworld, nether, end
?addbase [Base Name] [X Coordinate] [Y Coordinate] [Z Coordinate] [Tunnel Color] [Tunnel Position] [Side] [Dimension]
''' '''
player_name = get_nickname(ctx.message.author) player_name = get_nickname(ctx.message.author)
@ -75,7 +83,8 @@ async def addshop(ctx, name: str, x_pos: int, y_pos: int, z_pos: int, * args):
''' '''
Adds a shop to the database. Adds a shop to the database.
The tunnel address is optional. The tunnel address is optional.
?addbase [Shop name] [X Coordinate] [Y Coordinate] [Z Coordinate] [Tunnel Color] [Tunnel Position] The default dimension is the overworld. Valid options: overworld, nether, end
?addbase [Base Name] [X Coordinate] [Y Coordinate] [Z Coordinate] [Tunnel Color] [Tunnel Position] [Side] {Dimension]
''' '''
player_name = get_nickname(ctx.message.author) player_name = get_nickname(ctx.message.author)
@ -100,7 +109,7 @@ async def find(ctx, name: str):
loc_list = database.find_location_by_owner(name) loc_list = database.find_location_by_owner(name)
loc_string = loc_list_to_string(loc_list, '{} \n{}') loc_string = loc_list_to_string(loc_list, '{} \n{}')
await bot.say('{}, **{}** has **{}** base(s): \n {}'.format(ctx.message.author.mention, name, len(loc_list), await bot.say('{}, **{}** has **{}** locations(s): \n {}'.format(ctx.message.author.mention, name, len(loc_list),
loc_string)) loc_string))
except PlayerNotFound: except PlayerNotFound:
await bot.say('{}, the player **{}** is not in the database'.format(ctx.message.author.mention, name)) await bot.say('{}, the player **{}** is not in the database'.format(ctx.message.author.mention, name))
@ -123,7 +132,7 @@ async def delete(ctx, name: str):
@bot.command(pass_context=True) @bot.command(pass_context=True)
async def findaround(ctx, x_pos: int, z_pos: int, * args): async def findaround(ctx, x_pos: int, z_pos: int, * args):
''' '''
Finds all the bases/shops around a certain point that are registered in the database Finds all the locations around a certain point that are registered in the database
The Radius argument defaults to 200 blocks if no value is given The Radius argument defaults to 200 blocks if no value is given
?findbasearound [X Coordinate] [Z Coordinate] [Radius] ?findbasearound [X Coordinate] [Z Coordinate] [Radius]
''' '''
@ -140,23 +149,23 @@ async def findaround(ctx, x_pos: int, z_pos: int, * args):
if len(base_list) != 0: if len(base_list) != 0:
base_string = loc_list_to_string(base_list, '{} \n{}') base_string = loc_list_to_string(base_list, '{} \n{}')
await bot.say('{}, there are {} base(s) within {} blocks of that point: \n {}'.format( await bot.say('{}, there are {} locations(s) within {} blocks of that point: \n {}'.format(
ctx.message.author.mention, len(base_list), radius, base_string)) ctx.message.author.mention, len(base_list), radius, base_string))
else: else:
await bot.say('{}, there are no bases within {} blocks of that point' await bot.say('{}, there are no locations within {} blocks of that point'
.format(ctx.message.author.mention, radius)) .format(ctx.message.author.mention, radius))
@bot.command(pass_context=True) @bot.command(pass_context=True)
async def additem(ctx, shop_name: str, item_name: str, diamond_price: int): async def additem(ctx, shop_name: str, item_name: str, amount: int, diamond_price: int):
''' '''
Adds an item to a shop's inventory Adds an item to a shop's inventory. Amount for diamond price.
?additem [Shop name] [Item Name] [Price] ?additem [Shop name] [Item Name] [Amount] [Price]
''' '''
try: try:
player_name = get_nickname(ctx.message.author) player_name = get_nickname(ctx.message.author)
database.add_item(player_name, shop_name, item_name, diamond_price) database.add_item(player_name, shop_name, item_name, diamond_price, amount)
await bot.say('{}, **{}** has been added to the inventory of **{}**.'.format(ctx.message.author.mention, await bot.say('{}, **{}** has been added to the inventory of **{}**.'.format(ctx.message.author.mention,
item_name, shop_name)) item_name, shop_name))

View File

@ -8,7 +8,7 @@ class TestGeoffreyDatabase(TestCase):
def setUp(self): def setUp(self):
self.database = GeoffreyDatabase('sqlite:///:memory:') self.database = GeoffreyDatabase('sqlite:///:memory:')
self.owner = Player('ZeroHD') self.owner = Player('ZeroHD')
self.loc = Location('test', 1, 2, 3, self.owner, ['Green', 0]) self.loc = Location('test', 1, 2, 3, self.owner, ['Green', 0, 'Right'])
def test_add_object(self): def test_add_object(self):
self.database.add_object(self.loc) self.database.add_object(self.loc)
@ -43,41 +43,41 @@ class TestGeoffreyDatabase(TestCase):
self.assertRaises(DeleteEntryError, self.database.delete_entry, Location, expr) self.assertRaises(DeleteEntryError, self.database.delete_entry, Location, expr)
def test_add_shop(self): def test_add_shop(self):
shop = self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0]) shop = self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0, 'Right'])
self.assertEqual(type(shop), Shop) self.assertEqual(type(shop), Shop)
def test_add_two_shops(self): def test_add_two_shops(self):
shop1 = self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0]) shop1 = self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0, 'Right'])
shop2 = self.database.add_shop('ZeroHD', 'no u', 1, 2, 3, ['Green', 0]) shop2 = self.database.add_shop('ZeroHD', 'no u', 1, 2, 3, ['Green', 0, 'Right'])
loc_list = self.database.find_location_by_owner('ZeroHD') loc_list = self.database.find_location_by_owner('ZeroHD')
self.assertEqual(loc_list[1].id, shop2.id) self.assertEqual(loc_list[1].id, shop2.id)
def test_add_item(self): def test_add_item(self):
self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0]) self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0, "Right"])
self.database.add_item('ZeroHD', 'test', 'dirt', 1) self.database.add_item('ZeroHD', 'test', 'dirt', 1, 15)
shops = self.database.find_shop_selling_item('dirt') shops = self.database.find_shop_selling_item('dirt')
self.assertEqual(shops[0].name, 'test') self.assertEqual(shops[0].name, 'test')
def test_find_location_by_owner(self): def test_find_location_by_owner(self):
shop = self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0]) shop = self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0, "Right"])
loc_list = self.database.find_location_by_owner('ZeroHD') loc_list = self.database.find_location_by_owner('ZeroHD')
self.assertEqual(loc_list[0].id, shop.id) self.assertEqual(loc_list[0].id, shop.id)
def test_find_location_by_name_and_owner(self): def test_find_location_by_name_and_owner(self):
shop = self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0]) shop = self.database.add_shop('ZeroHD', 'test', 1, 2, 3, ['Green', 0, "Right"])
loc_list = self.database.find_location_by_name_and_owner('ZeroHD','test') loc_list = self.database.find_location_by_name_and_owner('ZeroHD','test')
self.assertEqual(loc_list[0].id, shop.id) self.assertEqual(loc_list[0].id, shop.id)
def test_delete_base(self): def test_delete_base(self):
self.database.add_location('ZeroHD', 'test', 1, 2, 3, ['Green', 0]) self.database.add_location('ZeroHD', 'test', 1, 2, 3, ['Green', 0, "Right"])
self.database.delete_base('ZeroHD', 'test') self.database.delete_base('ZeroHD', 'test')
@ -86,35 +86,35 @@ class TestGeoffreyDatabase(TestCase):
self.assertEqual(len(loc_list), 0) self.assertEqual(len(loc_list), 0)
def test_find_location_around(self): def test_find_location_around(self):
loc = self.database.add_location('ZeroHD', 'test', 0, 0, 0, ['Green', 0]) loc = self.database.add_location('ZeroHD', 'test', 0, 0, 0, ['Green', 0, "Right"])
loc_list = self.database.find_location_around(100, 100, 200) loc_list = self.database.find_location_around(100, 100, 100)
self.assertEqual(loc_list[0].name, loc.name) self.assertEqual(loc_list[0].name, loc.name)
loc_list = self.database.find_location_around(200, 200, 200) loc_list = self.database.find_location_around(200, 200, 100)
self.assertEqual(len(loc_list), 0) self.assertEqual(len(loc_list), 0)
def test_find_location_by_name(self): def test_find_location_by_name(self):
loc = self.database.add_location('ZeroHD', 'test', 0, 0, 0, ['Green', 0]) loc = self.database.add_location('ZeroHD', 'test', 0, 0, 0, ['Green', 0, "Right"])
loc_list = self.database.find_location_by_name('test') loc_list = self.database.find_location_by_name('test')
self.assertEqual(loc_list[0].name, loc.name) self.assertEqual(loc_list[0].name, loc.name)
def test_wrong_case(self): def test_wrong_case(self):
loc = self.database.add_location('ZeroHD', 'test', 0, 0, 0, ['Green', 0]) loc = self.database.add_location('ZeroHD', 'test', 0, 0, 0, ['Green', 0, "right"])
loc_list = self.database.find_location_by_owner('zerohd') loc_list = self.database.find_location_by_owner('zerohd')
self.assertEqual(loc_list[0].id, loc.id) self.assertEqual(loc_list[0].id, loc.id)
self.database.add_shop('ZeroHD', 'testshop', 1, 2, 3, ['Green', 0]) self.database.add_shop('ZeroHD', 'testshop', 1, 2, 3, ['Green', 0, "lEft", "neThEr"])
self.database.add_item('ZeroHD', 'testshop', 'dirt', 1) self.database.add_item('ZeroHD', 'testshop', 'dirt', 1, 15)
shops = self.database.find_shop_selling_item('Dirt') shops = self.database.find_shop_selling_item('Dirts')
self.assertEqual(shops[0].name, 'testshop') self.assertEqual(shops[0].name, 'testshop')
@ -122,6 +122,13 @@ class TestGeoffreyDatabase(TestCase):
self.assertEqual(loc_list[0].name, 'test') self.assertEqual(loc_list[0].name, 'test')
def test_big_input(self):
loc = self.database.add_location('ZeroHD',
'TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', 0, 0, 0, ['Green', 0, "Right"])
loc_list = self.database.find_location_by_owner('zerohd')
self.assertEqual(loc_list[0].id, loc.id)