diff --git a/api/commands.py b/api/commands.py index 2ea6a80..6938480 100644 --- a/api/commands.py +++ b/api/commands.py @@ -105,14 +105,14 @@ def add_location(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None, loc_t @command("POST") def register(player_name, discord_uuid): - ''' + """ :request: POST :param player_name: Minecraft in-game name :param discord_uuid: Discord UUID if registering from Discord :return: JSON representation of the new Player :raise: PlayerInDBError :help: Registers your Discord and Minecraft account with the the database - ''' + """ mc_uuid = grab_UUID(player_name) @@ -127,7 +127,7 @@ def register(player_name, discord_uuid): @command("POST") def add_base(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param x_pos: MC X Coordinate :param z_pos: MC Z Coordinate @@ -137,14 +137,14 @@ def add_base(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): :return: JSON representation of the new base :raises: EntryNameNotUniqueError, PlayerNotFound, LocationLookupError :help: Adds your base to the database. - ''' + """ return add_location(x_pos, z_pos, name=name, discord_uuid=discord_uuid, mc_uuid=mc_uuid, loc_type=Base) @command("POST") def add_shop(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param x_pos: MC X Coordinate :param z_pos: MC Z Coordinate @@ -154,14 +154,14 @@ def add_shop(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): :return: JSON representation of the new shop :raises: EntryNameNotUniqueError, PlayerNotFound, LocationLookupError :help: Adds your shop to the database. - ''' + """ return add_location(x_pos, z_pos, name=name, discord_uuid=discord_uuid, mc_uuid=mc_uuid, loc_type=Shop) @command("POST") def add_town(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param x_pos: MC X Coordinate :param z_pos: MC Z Coordinate @@ -171,14 +171,14 @@ def add_town(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): :return: JSON representation of the new town :raises: EntryNameNotUniqueError, PlayerNotFound, LocationLookupError :help: Adds your town to the database. - ''' + """ return add_location(x_pos, z_pos, name=name, discord_uuid=discord_uuid, mc_uuid=mc_uuid, loc_type=Town) @command("POST") def add_farm(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param x_pos: MC X Coordinate :param z_pos: MC Z Coordinate @@ -188,7 +188,7 @@ def add_farm(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): :return: JSON representation of the new town :raises: EntryNameNotUniqueError, PlayerNotFound, LocationLookupError :help: Adds your public farm to the database. - ''' + """ return add_location(x_pos, z_pos, name=name, discord_uuid=discord_uuid, mc_uuid=mc_uuid, loc_type=PublicFarm) @@ -196,7 +196,7 @@ def add_farm(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None): @command("POST") def add_tunnel(tunnel_direction, tunnel_number, location_name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param tunnel_direction: Tunnel Direction :param tunnel_number: Tunnel Coordinate @@ -206,7 +206,7 @@ def add_tunnel(tunnel_direction, tunnel_number, location_name=None, discord_uuid :return: JSON Representation of the Tunnel :raises: PlayerNotFound, LocationHasTunnelError, EntryNameNotUniqueError, NoLocationsInDatabase, InvalidTunnelError :help: Adds your tunnel to the database. - ''' + """ player = get_player(discord_uuid, mc_uuid) if location_name is None: loc = get_location(player) @@ -227,14 +227,14 @@ def add_tunnel(tunnel_direction, tunnel_number, location_name=None, discord_uuid @command("GET") def find_location(search, limit=25): - ''' + """ :request: GET :param search: Location name or owner to search for :param limit: How man locations to return :return: List of the matching locations :raises: LocationLookupError :help: Finds all the locations matching the search term - ''' + """ locations = Location.objects.filter(Q(name__icontains=search) | Q(owner__name__icontains=search)).all()[:limit] @@ -246,7 +246,7 @@ def find_location(search, limit=25): @command("POST") def delete(name, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param name: Name of location to delete :param discord_uuid: Discord UUID @@ -254,7 +254,7 @@ def delete(name, discord_uuid=None, mc_uuid=None): :return: Location Name :raises: LocationLookUpError :help: Deletes a location from the database - ''' + """ owner = get_player(discord_uuid, mc_uuid) try: @@ -267,7 +267,7 @@ def delete(name, discord_uuid=None, mc_uuid=None): @command("GET") def find_around(x_pos, z_pos, radius=200): - ''' + """ :request: GET :param x_pos: MC X Coordinate :param z_pos: MC Z Coordinate @@ -275,7 +275,7 @@ def find_around(x_pos, z_pos, radius=200): :return: List of all locations in the radius :raises: LocationLookupError :help: Finds all the locations around a certain point - ''' + """ x_pos = int(x_pos) z_pos = int(z_pos) @@ -292,7 +292,7 @@ def find_around(x_pos, z_pos, radius=200): @command("POST") def add_item(item_name, quantity, diamond_price, shop_name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param item_name: name of the item :param quantity: number of items being sold @@ -303,7 +303,7 @@ def add_item(item_name, quantity, diamond_price, shop_name=None, discord_uuid=No :return: Item Listing :raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase :help: Adds an item to a shop's inventory. - ''' + """ player = get_player(discord_uuid, mc_uuid) @@ -317,16 +317,16 @@ def add_item(item_name, quantity, diamond_price, shop_name=None, discord_uuid=No @command("POST") def add_resource(resource_name, farm_name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param resource_name: name of the resource - ;param farm_name: name of the farm to add the resource to. Can be none. + :param farm_name: name of the farm to add the resource to. Can be none. :param discord_uuid: Discord UUID :param mc_uuid: Minecraft UUID :return: Item Listing :raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase :help: Adds a resource to a farm. - ''' + """ player = get_player(discord_uuid, mc_uuid) @@ -347,26 +347,26 @@ def find_farm(resource_name): @command("GET") def selling(item_name): - ''' + """ :request: GET :param item_name: Item name to search for :return: List of top matching shops, sorted by the :raises: ItemNotFound :help: Lists shops selling an item. Sorted by when they were last restocked. - ''' + """ return get_selling(item_name, sort="-date_restocked") @command("GET") def selling_price(item_name): - ''' + """ :request: GET :param item_name: Item name to search for :return: List of top matching shops, sorted by the :raises: ItemNotFound :help: Lists shops selling an item. Sorted lowest price to highest price. - ''' + """ return get_selling(item_name, sort="normalized_price") @@ -409,13 +409,13 @@ def get_selling(item_name, sort): @command("GET") def info(location_name): - ''' + """ :request: GET :param location_name: Name of the location to get info on :return: JSON representation of location :raises: LocationLookupError :help: Finds all the locations matching the search term - ''' + """ location = Location.objects.filter(name__iexact=location_name).first() @@ -438,14 +438,14 @@ def info(location_name): @command("GET") def tunnel(player_name): - ''' + """ :request: GET :param player_name: MC player name :return: List of all the tunnels a user owns :raises: LocationLookUpError :raises: LocationLookupError :help: Finds all the tunnels a player owns - ''' + """ tunnels = Tunnel.objects.filter(location__owner__name__icontains=player_name).all() @@ -457,7 +457,7 @@ def tunnel(player_name): @command("POST") def edit_pos(x, z, loc_name, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param x: New MC X coordinate :param z: New MC Z Coordinate @@ -468,7 +468,7 @@ def edit_pos(x, z, loc_name, discord_uuid=None, mc_uuid=None): :raises: :raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase :help: Edits the position of a location - ''' + """ player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid) location = get_location(player, loc_name) @@ -482,7 +482,7 @@ def edit_pos(x, z, loc_name, discord_uuid=None, mc_uuid=None): @command("POST") def edit_tunnel(tunnel_direction, tunnel_number, loc_name, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param tunnel_direction: New Tunnel Direction :param tunnel_number: New Tunnel Address @@ -492,7 +492,7 @@ def edit_tunnel(tunnel_direction, tunnel_number, loc_name, discord_uuid=None, mc :return: Edited Location :raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase :help: Edits the tunnel of a location - ''' + """ player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid) location = get_location(player, loc_name) @@ -511,7 +511,7 @@ def edit_tunnel(tunnel_direction, tunnel_number, loc_name, discord_uuid=None, mc @command("POST") def edit_name(new_name, loc_name, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param new_name: New Location Name :param loc_name: Old Location name @@ -520,7 +520,7 @@ def edit_name(new_name, loc_name, discord_uuid=None, mc_uuid=None): :return: Edited Location :raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase :help: Edits the name of a location - ''' + """ player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid) @@ -536,7 +536,7 @@ def edit_name(new_name, loc_name, discord_uuid=None, mc_uuid=None): @command("POST") def delete_item(item, shop_name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param item: Item name to delete :param shop_name: Shop selling item, can be None if the user only has one shop @@ -545,7 +545,7 @@ def delete_item(item, shop_name=None, discord_uuid=None, mc_uuid=None): :return: Shop where the item was deleted from :raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase, ItemNotFound :help: Deletes an item from a shop - ''' + """ player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid) @@ -563,7 +563,7 @@ def delete_item(item, shop_name=None, discord_uuid=None, mc_uuid=None): @command("POST") def delete_resource(resource_name, farm_name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param resource: resource to delete :param farm_name: Farm with resource, can be None if the user only has one farm @@ -572,7 +572,7 @@ def delete_resource(resource_name, farm_name=None, discord_uuid=None, mc_uuid=No :return: PublicFarm where the resource was deleted from :raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase, ItemNotFound :help: Deletes a resource from a farm - ''' + """ player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid) @@ -590,14 +590,14 @@ def delete_resource(resource_name, farm_name=None, discord_uuid=None, mc_uuid=No @command("GET") def me(discord_uuid=None, mc_uuid=None): - ''' + """ :request: GET :param discord_uuid: Discord UUID :param mc_uuid: MC UUID :return: Returns a list of all the locations owned by a user :raises: NoLocationsInDatabase, PlayerNotFound :help: Find all the locations in the database - ''' + """ try: player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid) @@ -614,7 +614,7 @@ def me(discord_uuid=None, mc_uuid=None): @command("POST") def restock(item_name, shop_name=None, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param item_name: Item to restock :param shop_name: Shop the item is in, can be none if the only one location is owned by the user @@ -623,7 +623,7 @@ def restock(item_name, shop_name=None, discord_uuid=None, mc_uuid=None): :return: List of items updated :raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase, ItemNotFound :help: Restocks items matching the item name in your shop - ''' + """ owner = get_player(discord_uuid, mc_uuid) shop = get_location(owner, shop_name, Shop) @@ -641,7 +641,7 @@ def restock(item_name, shop_name=None, discord_uuid=None, mc_uuid=None): @command("POST") def add_owner(new_owner_name, location_name, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param new_owner_name: The MC username of the new owner :param location_name: The name of the location to add them to @@ -650,7 +650,7 @@ def add_owner(new_owner_name, location_name, discord_uuid=None, mc_uuid=None): :return: Update Location :raises: PlayerNotFound, LocationLookupError, IsOwnerError, OwnerNotFound :help: Adds a co-owner to a location - ''' + """ owner = get_player(discord_uuid, mc_uuid) try: @@ -672,7 +672,7 @@ def add_owner(new_owner_name, location_name, discord_uuid=None, mc_uuid=None): @command("POST") def add_resident(new_resident_name, town_name, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param new_resident_name: The MC username of the new resident :param town_name: The name of the town to add the resident to, can be blank if the owner has one town @@ -681,7 +681,7 @@ def add_resident(new_resident_name, town_name, discord_uuid=None, mc_uuid=None): :return: Updated Location :raises: PlayerNotFound, LocationLookupError, IsResidentError, ResidentNotFoundError :help: Adds a resident to a town - ''' + """ owner = get_player(discord_uuid, mc_uuid) try: @@ -704,7 +704,7 @@ def add_resident(new_resident_name, town_name, discord_uuid=None, mc_uuid=None): @command("POST") def remove_resident(resident_name, town_name, discord_uuid=None, mc_uuid=None): - ''' + """ :request: POST :param resident_name: Name of the resident to remove :param town_name: Name of the town, can be blank if the owner has one town @@ -713,7 +713,7 @@ def remove_resident(resident_name, town_name, discord_uuid=None, mc_uuid=None): :raises: PlayerNotFound, LocationLookupError, ResidentNotFoundError :return: Updated town :help: Removes a resident from a town - ''' + """ owner = get_player(discord_uuid, mc_uuid) town = get_location(owner, town_name, Town) diff --git a/models.py b/models.py index e96250c..c80e3e3 100644 --- a/models.py +++ b/models.py @@ -5,24 +5,25 @@ from sys import maxsize from GeoffreyApp.util import create_token, objects_list_to_json + # Create your models here. class APIToken(models.Model): key = models.CharField(default=create_token, max_length=25, unique=True) - ''' + """ Key used to access the Geoffrey API - ''' + """ name = models.CharField(max_length=50, blank=True) - ''' + """ Name of the key - ''' + """ commands_perm = models.BooleanField(default=False) - ''' + """ Permission to use the command api - ''' + """ def __str__(self): if len(self.name): @@ -32,27 +33,46 @@ class APIToken(models.Model): class Player(models.Model): + """ + Model of a Player + """ + name = models.CharField(max_length=30, unique=True) - ''' - Player username - ''' + """ + In Game Username + """ mc_uuid = models.CharField(max_length=36, unique=True) - ''' + """ Minecraft UUID - ''' + """ discord_uuid = models.CharField(max_length=50, unique=True) - ''' + """ Discord UUID - ''' + """ @property def loc_count(self): + """ + Number of locations the player is an owner of + """ return Location.objects.filter(owner=self).count() @property def json(self): + """ + JSON representation of the Player + + .. code-block:: json + + { + "name" : "self.name", + "mc_uuid": "self.mc_uuid", + "discord_uuid": "self.discord_uuid", + } + """ + return {"name": self.name, "mc_uuid": self.mc_uuid, "discord_uuid": self.discord_uuid @@ -63,40 +83,54 @@ class Player(models.Model): class Location(models.Model): + """Model of a Location""" + DIMENSIONS = ( ('O', 'Overworld'), ('N', 'Nether'), ('E', 'The End') ) + """ + Possible dimensions for a location to be in + """ name = models.CharField(max_length=128, unique=True) - ''' + """ Name of the location - ''' + """ x_coord = models.IntegerField() - ''' + """ X Position - ''' + """ z_coord = models.IntegerField() - ''' + """ Z Position - ''' + """ dimension = models.CharField(max_length=1, choices=DIMENSIONS) + """ + Dimension of Location + """ owner = models.ManyToManyField(Player) - ''' + """ Owner of Location - ''' + """ @property - def location(self): + def position(self): + """ + Formatted position of the location + """ return "(x={}, z={})".format(self.x_coord, self.z_coord) @property def tunnel(self): + """ + The tunnel associated if this location, None if no tunnel exists + """ try: tunnel = Tunnel.objects.get(location=self) except Tunnel.DoesNotExist: @@ -106,6 +140,9 @@ class Location(models.Model): @property def get_owners(self): + """ + List of all the owners of the location + """ owner_list = [] for owner in self.owner.all(): owner_list.append(owner.json) @@ -114,25 +151,47 @@ class Location(models.Model): @property def json(self): - return {"type": self.__class__.__name__, + """ + JSON representation of the location + + .. code-block:: json + + { + "type": "Base", + "name": "Location", + "x_coord": 0, + "z_coord": 0, + "dimension": "O", + "owner": [], + "tunnel": {}, + "link": "/GeoffreyApp/Base/1" + } + """ + return {"type": self.loc_type, "name": self.name, "x_coord": self.x_coord, "z_coord": self.z_coord, "dimension": self.dimension, "owner": self.get_owners, - "location": self.location, + "location": self.position, "tunnel": None if self.tunnel is None else self.tunnel.tunnel_str, "link": self.link } @property def loc_type(self): + """ + The name of the location type + """ str = self.loc_child_obj.__class__.__name__ return str @property def link(self): + """ + href to the location page + """ child = self.loc_child_obj if child != self: @@ -140,6 +199,9 @@ class Location(models.Model): @property def loc_child_obj(self): + """ + Child object + """ if hasattr(self, "shop"): return self.shop elif hasattr(self, "base"): @@ -153,6 +215,10 @@ class Location(models.Model): @property def dynmap_url(self): + """ + Link to the location on the dynmap, none if there is no dynmap + """ + base_url = getattr(settings, "GEOFFREY_DYNMAP_BASE_URL") world_name = getattr(settings, "GEOFFREY_DYNMAP_WORLD_NAME") if base_url is not None: @@ -172,6 +238,9 @@ class Shop(Location): @property def link(self): + """ + Link to the shop's page + """ return reverse("GeoffreyShopInfo", kwargs={"id": self.id}) @@ -181,23 +250,51 @@ class Base(Location): @property def link(self): + """ + Link to the base's page + """ return reverse("GeoffreyBaseInfo", kwargs={"id": self.id}) class Town(Location): residents = models.ManyToManyField(Player) + """ + Players who are members of the town + """ def __str__(self): return "Town: %s" % self.name @property def get_residents(self): + """ + List of residents in the town in JSON farm + """ + residents = self.residents.all() return objects_list_to_json(residents) @property def json(self): + """ + JSON representation of the town + + .. code-block:: json + + { + "type": "Town", + "name": "Location", + "x_coord": 0, + "z_coord": 0, + "dimension": "O", + "owner": [], + "tunnel": {}, + "link": "/GeoffreyApp/Base/1", + "residents": [] + } + """ + json = super().json json["residents"] = self.get_residents @@ -206,12 +303,18 @@ class Town(Location): @property def link(self): + """ + Link to the town's page + """ return reverse("GeoffreyTownInfo", kwargs={"id": self.id}) class PublicFarm(Location): @property def link(self): + """ + Link to the Farms's page + """ return reverse("GeoffreyPublicFarmInfo", kwargs={"id": self.id}) @@ -221,6 +324,16 @@ class Resource(models.Model): @property def json(self): + """ + JSON representation of the town + + .. code-block:: json + + { + "name": "Dirt" + "farm_id": 1 + } + """ return {"name": self.resource_name, "farm_id": self.farm_id } @@ -228,43 +341,62 @@ class Resource(models.Model): class ItemListing(models.Model): item_name = models.CharField(max_length=128) - ''' + """ Name of the item - ''' + """ price = models.IntegerField() - ''' + """ Number of diamonds per amount of items - ''' + """ amount = models.IntegerField() - ''' + """ Number of items - ''' + """ date_restocked = models.DateTimeField(auto_now=True) - ''' + """ Datetime the item was last restocked - ''' + """ shop = models.ForeignKey(Shop, related_name="shop_selling", on_delete=models.CASCADE) - ''' + """ Shop the item is sold at - ''' + """ @property def normalized_price(self): + """ + normalized price, price/amount + """ + if self.amount == 0: return maxsize else: - return self.price/self.amount + return self.price / self.amount @property def json(self): + """ + JSON representation of the item + + .. code-block:: json + + { + "item_name": "dirt", + "price": 1, + "amount": 1, + "date_restocked": 1553264508, + "normalized_price": 1, + "shop": {} + } + """ + return {"item_name": self.item_name, "price": self.price, "amount": self.amount, - "date_restocked": self.date_restocked, + "date_restocked": self.date_restocked.timestamp(), "normalized_price": self.normalized_price, "shop": self.shop.json, } @@ -280,30 +412,41 @@ class Tunnel(models.Model): ('S', getattr(settings, 'GEOFFREY_SOUTH_TUNNEL', '')), ('W', getattr(settings, 'GEOFFREY_WEST_TUNNEL', '')) ) - ''' + """ Tunnel Direction - ''' + """ tunnel_number = models.IntegerField() - ''' + """ Tunnel coordinate - ''' + """ tunnel_direction = models.CharField(max_length=1, choices=TUNNEL_NAMES) - ''' + """ Tunnel Direction - ''' + """ location = models.ForeignKey(Location, related_name="tunnel_location", on_delete=models.CASCADE) - ''' - Location that the tunnel is for - ''' + """ + Location that the tunnel is connected to + """ def __str__(self): return "Tunnel: %s %d" % (self.get_tunnel_direction_display(), self.tunnel_number) @property def json(self): + """ + JSON representation of the tunnel` + + .. code-block:: json + + { + "location_name": "Base", + "tunnel_direction": "N", + "tunnel_number": 500 + } + """ return {"location_name": self.location.name, "tunnel_direction": self.get_tunnel_direction_display(), "tunnel_number": self.tunnel_number @@ -311,4 +454,7 @@ class Tunnel(models.Model): @property def tunnel_str(self): + """ + formatted tunnel string + """ return "{} {}".format(self.get_tunnel_direction_display(), self.tunnel_number) diff --git a/test/test_commands.py b/test/test_commands.py index 614671c..fb5aabf 100644 --- a/test/test_commands.py +++ b/test/test_commands.py @@ -43,13 +43,13 @@ class CommandsAPITestCase(TestCase): self.farm.owner.add(self.player) def test_register(self): - register(player_name="Vakky", discord_uuid="229423434256351233") + register(player_name="DrVakky", discord_uuid="229423434256351233") count = Player.objects.filter(mc_uuid__iexact="7afbf6632bf049ef915f22e81b298d17").count() self.assertEqual(count, 1) - self.assertRaises(PlayerInDBError, register, player_name="Vakky", discord_uuid="229423434256351233") + self.assertRaises(PlayerInDBError, register, player_name="DrVakky", discord_uuid="229423434256351233") def test_add_base(self): add_base(x_pos=0, z_pos=0, name=None, discord_uuid=DISCORD_UUID) @@ -115,7 +115,7 @@ class CommandsAPITestCase(TestCase): self.populate() locations = find_around(x_pos=0, z_pos=0, radius=50) - self.assertEqual(len(locations), 1) + self.assertEqual(len(locations), 2) def test_selling(self): self.populate()