Geoffrey-Django/geoffrey/DatabaseModels.py

296 lines
9.5 KiB
Python
Raw Normal View History

2018-08-12 19:00:04 +00:00
import enum
from difflib import SequenceMatcher
from sqlalchemy import Column, Integer, String, ForeignKey, Enum, create_engine, exists
2018-07-21 18:28:31 +00:00
from sqlalchemy.exc import IntegrityError, DataError
from sqlalchemy.ext.declarative import declarative_base
2018-08-12 19:00:04 +00:00
from sqlalchemy.orm import relationship, column_property, sessionmaker
2018-07-21 18:28:31 +00:00
from sqlalchemy.sql import expression
2018-08-12 19:00:04 +00:00
from BotConfig import bot_config
from BotErrors import *
2018-06-03 02:42:31 +00:00
from MinecraftAccountInfoGrabber import *
2018-08-01 00:22:17 +00:00
SQL_Base = declarative_base()
def check_similarity(a, b):
ratio = SequenceMatcher(None, a, b).ratio()
if (ratio > 0.6) or (a[0] == b[0]):
return True
else:
return False
class GeoffreyDatabase:
def __init__(self, engine_args=bot_config.engine_args):
self.engine = create_engine(engine_args, pool_recycle=3600, pool_pre_ping=True)
self.Session = sessionmaker(bind=self.engine)
SQL_Base.metadata.create_all(self.engine)
def clear_all(self, session):
session.query(Tunnel).delete()
session.query(ItemListing).delete()
session.query(Shop).delete()
session.query(Location).delete()
session.query(Player).delete()
session.commit()
2018-07-21 22:22:28 +00:00
def add_object(self, session, obj):
try:
ret = session.query(exists().where(type(obj).id == obj.id))
if ret:
session.add(obj)
session.commit()
except IntegrityError:
session.rollback()
raise EntryNameNotUniqueError
2018-07-21 18:28:31 +00:00
except DataError:
session.rollback()
raise DatabaseValueError
except:
session.rollback()
def query_by_filter(self, session, obj_type, *args, limit=10):
filter_value = self.combine_filter(args)
return session.query(obj_type).filter(filter_value).limit(limit).all()
def delete_entry(self, session, obj_type, * args):
filter_value = self.combine_filter(args)
entry = session.query(obj_type).filter(filter_value)
if entry.first() is not None:
entry.delete()
else:
raise DeleteEntryError
session.commit()
def print_database(self, session, obj_type):
obj_list = session.query(obj_type).all()
2018-06-23 15:17:51 +00:00
s = ''
for obj in obj_list:
s = s + '\n' + obj.id
return s
def combine_filter(self, filter_value):
2018-07-21 18:28:31 +00:00
return expression.and_(filter_value[0])
class TunnelDirection(enum.Enum):
North = 'green'
East = 'blue'
South = 'red'
West = 'yellow'
def str_to_tunnel_dir(arg):
arg = arg.lower()
if check_similarity(TunnelDirection.North.value, arg):
return TunnelDirection.North
elif check_similarity(TunnelDirection.East.value, arg):
return TunnelDirection.East
elif check_similarity(TunnelDirection.South.value, arg):
return TunnelDirection.South
elif check_similarity(TunnelDirection.West.value, arg):
return TunnelDirection.West
else:
raise InvalidTunnelError
class Dimension(enum.Enum):
overworld = 'overworld'
nether = 'nether'
end = 'end'
def str_to_dimension(arg):
arg = arg.lower()
if check_similarity(Dimension.overworld.value, arg):
return Dimension.overworld
elif check_similarity(Dimension.nether.value, arg):
return Dimension.nether
elif check_similarity(Dimension.end.value, arg):
return Dimension.end
else:
raise InvalidDimError
class Player(SQL_Base):
__tablename__ = 'Players'
id = Column(Integer, primary_key=True, autoincrement=True)
2018-07-21 18:28:31 +00:00
mc_uuid = Column(String(128))
discord_uuid = Column(String(128))
name = Column(String(128))
locations = relationship("Location", back_populates="owner", lazy='dynamic',
cascade="save-update, merge, delete, delete-orphan", single_parent=True)
2018-07-21 18:28:31 +00:00
tunnels = relationship("Tunnel", back_populates="owner", lazy='dynamic',
cascade="save-update, merge, delete, delete-orphan")
def __init__(self, name, discord_id=None):
self.mc_uuid = grab_UUID(name)
self.discord_uuid = discord_id
2018-06-23 15:17:51 +00:00
self.name = name
class Tunnel(SQL_Base):
__tablename__ = 'Tunnels'
id = Column(Integer, primary_key=True, autoincrement=True)
tunnel_number = Column(Integer)
tunnel_direction = Column(Enum(TunnelDirection))
owner_id = Column(Integer, ForeignKey('Players.id'))
owner = relationship("Player", back_populates="tunnels", cascade="save-update, merge, delete")
2018-07-21 18:28:31 +00:00
location_id = Column(Integer, ForeignKey('Locations.id', ondelete='CASCADE'))
location = relationship("Location", back_populates="tunnel", lazy="joined")
def __init__(self, owner, tunnel_color, tunnel_number, location=None):
try:
self.owner = owner
self.location = location
self.tunnel_direction = TunnelDirection.str_to_tunnel_dir(tunnel_color)
self.tunnel_number = tunnel_number
except (ValueError, IndexError):
raise TunnelInitError
2018-07-23 01:03:24 +00:00
def full_str(self):
2018-07-29 15:50:24 +00:00
if self.location is None:
string = 'Tunnel: **{}**'.format(self.__str__())
else:
string = 'Location: **{}** Tunnel: **{}**'.format(self.location.name, self.__str__())
return string
2018-07-23 01:03:24 +00:00
def __str__(self):
return '{} {}'.format(self.tunnel_direction.value.title(), self.tunnel_number)
class Location(SQL_Base):
__tablename__ = 'Locations'
id = Column(Integer, primary_key=True)
name = Column(String(128), unique=True)
x = Column(Integer)
z = Column(Integer)
2018-07-21 18:28:31 +00:00
tunnel = relationship("Tunnel", uselist=False, cascade="all, delete-orphan")
dimension = Column(Enum(Dimension))
2018-07-21 18:28:31 +00:00
owner_id = Column(Integer, ForeignKey('Players.id', ondelete='CASCADE'))
owner = relationship("Player", back_populates="locations", cascade="all, delete-orphan", single_parent=True)
type = Column(String(128))
2018-06-23 17:33:02 +00:00
2018-06-02 21:41:27 +00:00
__mapper_args__ = {
'polymorphic_on': type,
'polymorphic_identity': 'Location'
}
def __init__(self, name, x, z, owner, dimension):
try:
self.name = name
self.x = x
self.z = z
2018-06-23 15:17:51 +00:00
self.owner = owner
if self.dimension is not None:
self.dimension = self.dimension = Dimension.str_to_dimension(dimension)
else:
self.dimension = Dimension.overworld
except (ValueError, IndexError):
raise LocationInitError
def dynmap_link(self):
2018-08-10 02:44:50 +00:00
return '<{}/?worldname={}&mapname=surface&zoom=4&x={}&y=65&z={}>'.\
format(bot_config.dynmap_url, bot_config.world_name, self.x, self.z)
def pos_to_str(self):
2018-08-18 14:31:43 +00:00
pos_str = '**(x= {}, z= {})** **{}**'.format(self.x, self.z, self.dimension.value.title())
if self.tunnel is not None:
return pos_str + ', **{}**'.format(self.tunnel)
else:
return pos_str
def info_str(self):
2018-08-18 14:31:43 +00:00
return "**{}** @ {}, Owner: **{}**, Type: **{}**".format(self.name, self.pos_to_str(), self.owner.name,
self.type)
def full_str(self):
return self.__str__() + '\n' + self.dynmap_link()
def __str__(self):
2018-08-18 14:31:43 +00:00
return self.info_str()
2018-06-23 17:33:02 +00:00
2018-06-02 21:41:27 +00:00
2018-08-01 00:22:17 +00:00
class Base(Location):
__tablename__ = 'Bases'
base_id = Column(Integer, ForeignKey('Locations.id', ondelete='CASCADE'), primary_key=True)
name = column_property(Column(String(128)), Location.name)
__mapper_args__ = {
'polymorphic_identity': 'Base',
}
2018-06-02 21:41:27 +00:00
class Shop(Location):
__tablename__ = 'Shops'
2018-07-21 18:28:31 +00:00
shop_id = Column(Integer, ForeignKey('Locations.id', ondelete='CASCADE'), primary_key=True)
name = column_property(Column(String(128)), Location.name)
inventory = relationship('ItemListing', back_populates='shop', cascade='all, delete-orphan', lazy='dynamic')
2018-06-02 21:41:27 +00:00
__mapper_args__ = {
2018-06-23 17:33:02 +00:00
'polymorphic_identity': 'Shop',
2018-06-02 21:41:27 +00:00
}
def inv_to_str(self):
if len(self.inventory.all()) != 0:
inv = '\n**Inventory**:'
str_format = '{}\n{}'
for item in self.inventory:
inv = str_format.format(inv, item.listing_str())
return inv
else:
return ''
def full_str(self):
return Location.full_str(self) + self.inv_to_str()
def __str__(self):
return Location.__str__(self)
def __init__(self, name, x, z, owner, dimension=None):
Location.__init__(self, name, x, z, owner, dimension)
2018-06-02 21:41:27 +00:00
class ItemListing(SQL_Base):
__tablename__ = 'Items'
id = Column(Integer, primary_key=True, autoincrement=True)
2018-07-21 18:28:31 +00:00
name = Column(String(128))
2018-06-02 21:41:27 +00:00
price = Column(Integer)
amount = Column(Integer)
2018-06-02 21:41:27 +00:00
2018-07-21 18:28:31 +00:00
shop_id = Column(Integer, ForeignKey('Shops.shop_id', ondelete='CASCADE'))
shop = relationship("Shop", back_populates="inventory", single_parent=True)
2018-06-02 21:41:27 +00:00
def __init__(self, name, price, amount, shop):
2018-06-02 21:41:27 +00:00
self.name = name
self.price = price
self.amount = amount
self.shop = shop
2018-06-02 21:41:27 +00:00
def listing_str(self):
2018-08-18 14:31:43 +00:00
return '**{}** **{}** for **{}D**'.format(self.amount, self.name, self.price)
2018-06-02 21:41:27 +00:00
def __str__(self):
2018-08-18 14:31:43 +00:00
return '**{}**, selling {}'.format(self.shop.name, self.listing_str())