yes am pro web dev yes
+ tweaked a few commands + added exception raised from the commands in the docs + added models to the documentation + Now using Bootstrap with the Superhero theme + Replaced side navbar with a top navbar + Added global search that works like the find command + Added a templatetag for generating the navbar + Layout likely to change again, but at least it has a nice theme now...doc_update
parent
0dbb2c95a4
commit
6cdfe76505
|
@ -4,6 +4,7 @@ from GeoffreyApp.errors import *
|
|||
from GeoffreyApp.minecraft_api import *
|
||||
import inspect
|
||||
import datetime
|
||||
import re
|
||||
|
||||
command_dict = {"GET": {}, "POST": {}, "DELETE": {}}
|
||||
|
||||
|
@ -35,12 +36,15 @@ def command(type):
|
|||
|
||||
|
||||
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
|
||||
try:
|
||||
if discord_uuid is not None:
|
||||
player = Player.objects.get(discord_uuid__iexact=discord_uuid)
|
||||
elif mc_uuid is not None:
|
||||
player = Player.objects.get(mc_uuid__iexact=mc_uuid)
|
||||
else:
|
||||
raise AttributeError
|
||||
except Player.DoesNotExist:
|
||||
raise PlayerNotFound
|
||||
|
||||
return player
|
||||
|
||||
|
@ -71,13 +75,13 @@ def add_location(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None, loc_t
|
|||
try:
|
||||
get_location(player, name, loc_type=loc_type)
|
||||
raise EntryNameNotUniqueError
|
||||
except (Location.DoesNotExist, NoLocationsInDatabase):
|
||||
except (Location.DoesNotExist, NoLocationsInDatabase, LocationLookUpError):
|
||||
if name is None:
|
||||
name = "{}'s {}".format(player.name, loc_type.__name__)
|
||||
|
||||
location = loc_type.objects.create(owner=player, name=name, x_coord=x_pos, z_coord=z_pos)
|
||||
location = loc_type.objects.create(owner=player, name=name, x_coord=x_pos, z_coord=z_pos)
|
||||
|
||||
return location.json
|
||||
return location.json
|
||||
|
||||
|
||||
@command("POST")
|
||||
|
@ -87,13 +91,19 @@ def register(player_name, discord_uuid):
|
|||
: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)
|
||||
player = Player.objects.create(name=player_name, mc_uuid=mc_uuid, discord_uuid=discord_uuid)
|
||||
|
||||
return player.json
|
||||
try:
|
||||
get_player(mc_uuid=mc_uuid)
|
||||
raise PlayerInDBError
|
||||
except Player.DoesNotExist:
|
||||
player = Player.objects.create(name=player_name, mc_uuid=mc_uuid, discord_uuid=discord_uuid)
|
||||
player.save()
|
||||
return player.json
|
||||
|
||||
|
||||
@command("POST")
|
||||
|
@ -106,6 +116,7 @@ def add_base(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None):
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: Minecraft UUID
|
||||
:return: JSON representation of the new base
|
||||
:raises: EntryNameNotUniqueError, PlayerNotFound, LocationLookupError
|
||||
:help: Adds your base to the database. The base name is optional if this is your first base
|
||||
'''
|
||||
|
||||
|
@ -122,6 +133,7 @@ def add_shop(x_pos, z_pos, name=None, discord_uuid=None, mc_uuid=None):
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: Minecraft UUID
|
||||
:return: JSON representation of the new shop
|
||||
:raises: EntryNameNotUniqueError, PlayerNotFound, LocationLookupError
|
||||
:help: Adds your shop to the database. The name is optional if this is your first shop
|
||||
'''
|
||||
|
||||
|
@ -138,12 +150,23 @@ def add_tunnel(tunnel_direction, tunnel_number, location_name=None, discord_uuid
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: Minecraft UUID
|
||||
:return: JSON Representation of the Tunnel
|
||||
:raises: PlayerNotFound, LocationHasTunnelError, EntryNameNotUniqueError, NoLocationsInDatabase
|
||||
:help: Adds your tunnel to the database. If you only have one location, you do not need to specify a location name
|
||||
'''
|
||||
player = get_player(discord_uuid, mc_uuid)
|
||||
if location_name is None:
|
||||
loc = get_location(player, name=location_name)
|
||||
loc = get_location(player)
|
||||
location_name = loc.name
|
||||
else:
|
||||
loc = get_location(player, name=location_name)
|
||||
|
||||
for direction in Tunnel.TUNNEL_NAMES:
|
||||
if re.search("{}.*".format(tunnel_direction), direction[1], re.IGNORECASE):
|
||||
tunnel_direction = direction[0]
|
||||
break
|
||||
|
||||
if Tunnel.objects.filter(location=loc).first():
|
||||
raise LocationHasTunnelError
|
||||
|
||||
tunnel = Tunnel.objects.create(tunnel_direction=tunnel_direction, tunnel_number=tunnel_number,
|
||||
location=get_location(player, location_name))
|
||||
|
@ -152,14 +175,15 @@ def add_tunnel(tunnel_direction, tunnel_number, location_name=None, discord_uuid
|
|||
|
||||
|
||||
@command("GET")
|
||||
def find_location(search):
|
||||
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
|
||||
'''
|
||||
limit = 25
|
||||
|
||||
locations = Location.objects.filter(Q(name__icontains=search) | Q(owner__name__icontains=search)).all()[:limit]
|
||||
|
||||
|
@ -177,12 +201,17 @@ def delete(name, discord_uuid=None, mc_uuid=None):
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: Minecraft UUID
|
||||
:return: Location Name
|
||||
:raises: LocationLookUpError
|
||||
:help: Deletes a location from the database
|
||||
'''
|
||||
owner = get_player(discord_uuid, mc_uuid)
|
||||
Location.objects.get(name__iexact=name, owner=owner).delete()
|
||||
return name
|
||||
|
||||
owner = get_player(discord_uuid, mc_uuid)
|
||||
try:
|
||||
Location.objects.get(name__iexact=name, owner=owner).delete()
|
||||
except Location.DoesNotExist:
|
||||
raise LocationLookUpError
|
||||
|
||||
return name
|
||||
|
||||
@command("GET")
|
||||
def find_around(x_pos, z_pos, radius=200):
|
||||
|
@ -192,12 +221,16 @@ def find_around(x_pos, z_pos, radius=200):
|
|||
:param z_pos: MC Z Coordinate
|
||||
:param radius: Radius to each around (default 200)
|
||||
:return: List of all locations in the radius
|
||||
:raises: LocationLookupError
|
||||
:help: Finds all the locations around a certain point
|
||||
'''
|
||||
|
||||
locations = Location.objects.filter(x_coord__range=(x_pos - radius, x_pos + radius),
|
||||
z_coord__range=(z_pos - radius, z_pos + radius)).all()
|
||||
|
||||
if len(locations) == 0:
|
||||
raise LocationLookUpError
|
||||
|
||||
return objects_list_to_json(locations)
|
||||
|
||||
|
||||
|
@ -212,6 +245,7 @@ def add_item(item_name, quantity, diamond_price, shop_name=None, discord_uuid=No
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: Minecraft UUID
|
||||
:return: Item Listing
|
||||
:raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase
|
||||
:help: Adds an item to a shop's inventory. If you have one shop, the shop name is not required
|
||||
'''
|
||||
|
||||
|
@ -219,18 +253,20 @@ def add_item(item_name, quantity, diamond_price, shop_name=None, discord_uuid=No
|
|||
|
||||
shop = get_location(player, shop_name, Shop).shop
|
||||
|
||||
item_listing = ItemListing.objects.create(shop=shop, amount=quantity, price=diamond_price, item_name=item_name)
|
||||
item_listing = ItemListing.objects.create(shop=shop, amount=int(quantity), price=int(diamond_price),
|
||||
item_name=item_name)
|
||||
|
||||
return item_listing.json
|
||||
|
||||
|
||||
@command("GET")
|
||||
def selling(item_name, sort="normalized_price"):
|
||||
def selling(item_name, sort="-date_restocked"):
|
||||
'''
|
||||
:request: GET
|
||||
:param item_name: Item name to search for
|
||||
:param sort: Field to sort shop results by, default is normalized_price
|
||||
:param sort: Field to sort shop results by, default is date_restocked
|
||||
:return: List of top matching shops, sorted by the
|
||||
:raises: ItemNotFound
|
||||
:help: Lists shops selling an item.
|
||||
'''
|
||||
|
||||
|
@ -271,7 +307,7 @@ def info(location_name):
|
|||
:request: GET
|
||||
:param location_name: Name of the location to get info on
|
||||
:return: JSON representation of location
|
||||
:raise LocationLookupError: If no location is found
|
||||
:raises: LocationLookupError
|
||||
:help: Finds all the locations matching the search term
|
||||
'''
|
||||
|
||||
|
@ -292,6 +328,8 @@ 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
|
||||
'''
|
||||
|
||||
|
@ -312,7 +350,9 @@ def edit_pos(x, z, loc_name, discord_uuid=None, mc_uuid=None):
|
|||
:param loc_name: Location Name to edit
|
||||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: MC UUID
|
||||
:return: Edited Location
|
||||
:return: Edited Locatio
|
||||
:raises:
|
||||
:raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase
|
||||
:help: Edits the position of a location
|
||||
'''
|
||||
|
||||
|
@ -336,6 +376,7 @@ def edit_tunnel(tunnel_direction, tunnel_number, loc_name, discord_uuid=None, mc
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: Minecraft UUID
|
||||
:return: Edited Location
|
||||
:raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase
|
||||
:help: Edits the tunnel of a location
|
||||
'''
|
||||
|
||||
|
@ -360,6 +401,7 @@ def edit_name(new_name, loc_name, discord_uuid=None, mc_uuid=None):
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: MC UUID
|
||||
:return: Edited Location
|
||||
:raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase
|
||||
:help: Edits the name of a location
|
||||
'''
|
||||
|
||||
|
@ -381,6 +423,8 @@ def delete_item(item, shop_name=None, discord_uuid=None, mc_uuid=None):
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: Minecraft UUID
|
||||
:return: Deletes an item from the database
|
||||
:raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase
|
||||
:help: Deletes an item from a shop
|
||||
'''
|
||||
|
||||
player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid)
|
||||
|
@ -399,15 +443,19 @@ def me(discord_uuid=None, mc_uuid=None):
|
|||
: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
|
||||
'''
|
||||
|
||||
player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid)
|
||||
try:
|
||||
player = get_player(discord_uuid=discord_uuid, mc_uuid=mc_uuid)
|
||||
except Player.DoesNotExist:
|
||||
raise PlayerNotFound
|
||||
|
||||
locations = Location.objects.filter(owner=player).all()
|
||||
|
||||
if len(locations) == 0:
|
||||
raise PlayerNotFound
|
||||
raise NoLocationsInDatabase
|
||||
|
||||
return objects_list_to_json(locations)
|
||||
|
||||
|
@ -421,6 +469,7 @@ def restock(item_name, shop_name=None, discord_uuid=None, mc_uuid=None):
|
|||
:param discord_uuid: Discord UUID
|
||||
:param mc_uuid: Minecraft UUID
|
||||
:return: List of items updated
|
||||
:raises: PlayerNotFound, LocationLookupError, EntryNameNotUniqueError, NoLocationsInDatabase
|
||||
:help: Restocks items matching the item name in your shop
|
||||
'''
|
||||
owner = get_player(discord_uuid, mc_uuid)
|
||||
|
|
|
@ -13,3 +13,4 @@ goods.
|
|||
|
||||
getting_started
|
||||
commands
|
||||
models
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
.. _models:
|
||||
|
||||
Models
|
||||
======
|
||||
Models used in Geoffrey
|
||||
|
||||
.. autoclass:: GeoffreyApp.models.APIToken
|
||||
:members:
|
||||
|
||||
.. autoclass:: GeoffreyApp.models.Player
|
||||
:members:
|
||||
|
||||
.. autoclass:: GeoffreyApp.models.Location
|
||||
:members:
|
||||
|
||||
.. autoclass:: GeoffreyApp.models.Shop
|
||||
:members:
|
||||
|
||||
.. autoclass:: GeoffreyApp.models.Base
|
||||
:members:
|
||||
|
||||
.. autoclass:: GeoffreyApp.models.ItemListing
|
||||
:members:
|
||||
|
||||
.. autoclass:: GeoffreyApp.models.Tunnel
|
||||
:members:
|
||||
|
78
models.py
78
models.py
|
@ -9,8 +9,19 @@ from GeoffreyApp.util import create_token
|
|||
|
||||
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):
|
||||
|
@ -21,8 +32,19 @@ class APIToken(models.Model):
|
|||
|
||||
class Player(models.Model):
|
||||
name = models.CharField(max_length=30, unique=True)
|
||||
'''
|
||||
Player 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 json(self):
|
||||
|
@ -43,12 +65,26 @@ class Location(models.Model):
|
|||
)
|
||||
|
||||
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)
|
||||
|
||||
owner = models.ForeignKey(Player, related_name='owner_player', on_delete=models.CASCADE)
|
||||
'''
|
||||
Owner of Location
|
||||
'''
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
|
@ -76,10 +112,29 @@ class Base(Location):
|
|||
|
||||
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):
|
||||
|
@ -93,26 +148,41 @@ class ItemListing(models.Model):
|
|||
return {"item_name": self.item_name,
|
||||
"price": self.price,
|
||||
"amount": self.amount,
|
||||
"date_restocked": self.date_restocked,
|
||||
"normalized_price": self.normalized_price,
|
||||
"shop": self.shop.json,
|
||||
}
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "Item: %d %s for %d" % (self.amount, self.item_name, self.amount)
|
||||
|
||||
|
||||
class Tunnel(models.Model):
|
||||
TUNNEL_NAMES = (
|
||||
('N', getattr(settings, 'NORTH', '')),
|
||||
('E', getattr(settings, 'EAST', '')),
|
||||
('S', getattr(settings, 'SOUTH', '')),
|
||||
('W', getattr(settings, 'WEST', ''))
|
||||
('N', getattr(settings, 'GEOFFREY_NORTH_TUNNEL', '')),
|
||||
('E', getattr(settings, 'GEOFFREY_EAST_TUNNEL', '')),
|
||||
('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
|
||||
'''
|
||||
|
||||
def __str__(self):
|
||||
return "Tunnel: %s %d" % (self.tunnel_direction, self.tunnel_number)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,25 +0,0 @@
|
|||
.sidebar-nav {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 200px;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.sidebar-option{
|
||||
float: left;
|
||||
}
|
||||
|
||||
.sidebar-option .sidebar-a {
|
||||
display: block;
|
||||
color: #000;
|
||||
padding: 8px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Change the link color on hover */
|
||||
.sidebar-option .sidebar-a:hover {
|
||||
background-color: #555;
|
||||
color: white;
|
||||
}
|
||||
|
|
@ -1,44 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
{% load static %}
|
||||
|
||||
{% load navbar %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="shortcut icon" type="image/png" href="{% static 'GeoffreyApp/img/icon.png' %}"/>
|
||||
<meta charset="UTF-8">
|
||||
{% block title %}<title>GeoffreyApp</title>{% endblock %}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
|
||||
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||
<!-- Add additional CSS in static file -->
|
||||
|
||||
<!-- jQuery library -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
|
||||
<!-- Popper JS -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
|
||||
|
||||
<!-- Latest compiled JavaScript -->
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
|
||||
{% load static %}
|
||||
<link rel="stylesheet" href="{% static 'GeoffreyApp/css/style.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'GeoffreyApp/css/bootstrap.css' %}">
|
||||
</head>
|
||||
<body>
|
||||
<body>
|
||||
<nav class="navbar">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a<img src="{% static 'GeoffreyApp/img/icon.png' %}" alt="Sed" height="100" width="100"/>
|
||||
<a class="navbar-brand" style="color:inherit;cursor:default;">Geoffrey</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
{% block sidebar %}
|
||||
<ul class="sidebar-nav">
|
||||
<li class="sidebar-option"><a class="sidebar-a" href="{% url 'GeoffreyHome' %}">Home</a></li>
|
||||
<li class="sidebar-option"><a class="sidebar-a" href="{% url 'GeoffreyPlayers' %}">Players</a></li>
|
||||
<li class="sidebar-option"><a class="sidebar-a" href="{% url 'GeoffreyBases' %}">Bases</a></li>
|
||||
<li class="sidebar-option"><a class="sidebar-a" href="{% url 'GeoffreyShops' %}">Shops</a></li>
|
||||
<li class="sidebar-option"><a class="sidebar-a" href="{% url 'GeoffreyItems' %}">Items</a></li>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<a href="#" class="navbar-left"><img src="{% static 'GeoffreyApp/img/icon.png' %}" height="30px" alt="sed"></a>
|
||||
<a class="navbar-brand" href="#">Geoffrey</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar"
|
||||
aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbar">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
{% autoescape off %}{% get_navbar current_page|safe %}{% endautoescape %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="col-sm-10 ">{% block content %}{% endblock %}</div>
|
||||
<form class="form-inline my-2 my-lg-0" id="searchform" action="{% url 'GeoffreySearch' %}">
|
||||
<input class="form-control mr-sm-2" name="search" type="text" placeholder="Search">
|
||||
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
|
||||
{% block search %}{% endblock %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "GeoffreyApp/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Geoffrey Minecraft Database Home</h1>
|
||||
<h2>Geoffrey Minecraft Database Home</h2>
|
||||
<p>Geoffrey is a database for storing information on Players, Bases, Shops, Towns, and more! </p>
|
||||
<p>Current Database Count:</p>
|
||||
<ul>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{% extends "GeoffreyApp/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Items</h1>
|
||||
{% if itemlisting_list %}
|
||||
<ul>
|
||||
{% for item in itemlisting_list %}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "GeoffreyApp/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Players</h1>
|
||||
|
||||
{% if player_list %}
|
||||
<ul>
|
||||
{% for player in player_list %}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
{% extends "GeoffreyApp/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h4>Search results for {{ search }}...</h4>
|
||||
|
||||
{% if player_list %}
|
||||
<h6>Players</h6>
|
||||
<ul>
|
||||
{% for player in player_list %}
|
||||
<li>
|
||||
{{ player.name }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% endif %}
|
||||
|
||||
{% if base_list %}
|
||||
<h6>Bases</h6>
|
||||
<ul>
|
||||
{% for base in base_list %}
|
||||
<li>
|
||||
{{ base.name }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% endif %}
|
||||
|
||||
{% if shop_list %}
|
||||
<h6>Shops</h6>
|
||||
<ul>
|
||||
{% for shop in shop_list %}
|
||||
<li>
|
||||
{{ shop.name }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -3,12 +3,6 @@
|
|||
{% block content %}
|
||||
<h1>Shops</h1>
|
||||
|
||||
<form id="searchform" action="{% url 'GeoffreyShops' %}" method="get" accept-charset="utf-8">
|
||||
<button class="searchbutton" type="submit">
|
||||
<i class="fa fa-search">Go</i>
|
||||
</button>
|
||||
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
|
||||
</form>
|
||||
{% if shop_list %}
|
||||
<ul>
|
||||
{% for shop in shop_list %}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
from django import template
|
||||
from django.urls import reverse
|
||||
|
||||
register = template.Library()
|
||||
|
||||
navbar_options = [
|
||||
("Home", reverse("GeoffreyHome")),
|
||||
("Players", reverse("GeoffreyPlayers")),
|
||||
("Shops", reverse("GeoffreyShops")),
|
||||
("Bases", reverse("GeoffreyBases")),
|
||||
("Item Listings", reverse("GeoffreyItems"))
|
||||
]
|
||||
|
||||
option_format = '<li class="nav-item{}"> <a class="nav-link" href="{}">{} </a> </li>'
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def get_navbar(page):
|
||||
navbar = ""
|
||||
|
||||
for option in navbar_options:
|
||||
if page == option[0]:
|
||||
active = ' active'
|
||||
else:
|
||||
active = ''
|
||||
|
||||
navbar += option_format.format(active, option[1], option[0])
|
||||
|
||||
return navbar
|
|
@ -39,6 +39,8 @@ class CommandsAPITestCase(TestCase):
|
|||
|
||||
self.assertEqual(count, 1)
|
||||
|
||||
self.assertRaises(PlayerInDBError, register, player_name="Vakky", discord_uuid="229423434256351233")
|
||||
|
||||
def test_add_base(self):
|
||||
add_base(x_pos=0, z_pos=0, name=None, discord_uuid=DISCORD_UUID)
|
||||
|
||||
|
@ -46,6 +48,8 @@ class CommandsAPITestCase(TestCase):
|
|||
|
||||
self.assertEqual(base.owner.name, "ZeroHD")
|
||||
|
||||
self.assertRaises(EntryNameNotUniqueError, add_base, x_pos=0, z_pos=0, name=None, discord_uuid=DISCORD_UUID)
|
||||
|
||||
def test_add_shop(self):
|
||||
add_shop(x_pos=0, z_pos=0, name=None, discord_uuid=DISCORD_UUID)
|
||||
|
||||
|
|
1
urls.py
1
urls.py
|
@ -7,5 +7,6 @@ urlpatterns = [
|
|||
url(r'^shops$', views.ShopList.as_view(), name='GeoffreyShops'),
|
||||
url(r'^bases$', views.BaseList.as_view(), name='GeoffreyBases'),
|
||||
url(r'^items$', views.ItemListingList.as_view(), name='GeoffreyItems'),
|
||||
url(r'^search$', views.SearchList.as_view(), name='GeoffreySearch'),
|
||||
]
|
||||
|
||||
|
|
35
views.py
35
views.py
|
@ -20,18 +20,44 @@ class Home(View):
|
|||
"num_bases": base_num,
|
||||
"num_shops": shop_num,
|
||||
"num_items": item_num,
|
||||
"current_page": "Home",
|
||||
}
|
||||
|
||||
return render(request, 'GeoffreyApp/home.html', context=context)
|
||||
|
||||
|
||||
class SearchList(View):
|
||||
def get(self, request):
|
||||
context = {}
|
||||
query = request.GET.get('search')
|
||||
context["search"] = query
|
||||
|
||||
context["player_list"] = Player.objects.filter(Q(name__icontains=query)).all()
|
||||
|
||||
context["base_list"] = Base.objects.filter(Q(name__icontains=query) | Q(owner__name__icontains=query)).all()
|
||||
|
||||
context["shop_list"] = Shop.objects.filter(Q(name__icontains=query) | Q(owner__name__icontains=query)).all()
|
||||
|
||||
return render(request, 'GeoffreyApp/search.html', context=context)
|
||||
|
||||
|
||||
class PlayerList(generic.ListView):
|
||||
model = Player
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['current_page'] = "Players"
|
||||
return context
|
||||
|
||||
|
||||
class ShopList(generic.ListView):
|
||||
model = Shop
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['current_page'] = "Shops"
|
||||
return context
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Shop.objects.all()
|
||||
|
||||
|
@ -45,7 +71,16 @@ class ShopList(generic.ListView):
|
|||
class BaseList(generic.ListView):
|
||||
model = Base
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['current_page'] = "Bases"
|
||||
return context
|
||||
|
||||
|
||||
class ItemListingList(generic.ListView):
|
||||
model = ItemListing
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['current_page'] = "Item Listings"
|
||||
return context
|
||||
|
|
Loading…
Reference in New Issue