From ec49b7c873e52fc9fe04f7b1ec1a08bf7980d7ad Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 16 Aug 2020 12:06:51 -0500 Subject: [PATCH] First pass of a GraphQL API + All location types can be queried based on name or id + If no query parameters are provided, all locations are returned + Integrated with the api tokens for the other APIs --- GeoffreyApp/api/models.py | 1 - GeoffreyApp/api/schema.py | 189 ++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 3 files changed, 190 insertions(+), 2 deletions(-) delete mode 100644 GeoffreyApp/api/models.py create mode 100644 GeoffreyApp/api/schema.py diff --git a/GeoffreyApp/api/models.py b/GeoffreyApp/api/models.py deleted file mode 100644 index 137941f..0000000 --- a/GeoffreyApp/api/models.py +++ /dev/null @@ -1 +0,0 @@ -from django.db import models diff --git a/GeoffreyApp/api/schema.py b/GeoffreyApp/api/schema.py new file mode 100644 index 0000000..93150a7 --- /dev/null +++ b/GeoffreyApp/api/schema.py @@ -0,0 +1,189 @@ +import graphene +from django.http import JsonResponse +from graphene_django import DjangoObjectType + +from GeoffreyApp.models import * +from GeoffreyApp.api.key import check_key + + +class UnauthorizedQuery(Exception): + """ + Unauthorized Query + """ + + def __init__(self): + super().__init__("GraphQL Request Not Authorized") + +class PlayerType(DjangoObjectType): + class Meta: + model = Player + fields = ("id", "name", "discord_uuid", "mc_uuid") + + +class TunnelType(DjangoObjectType): + class Meta: + model = Tunnel + fields = ("tunnel_number", "tunnel_direction") + + +class ItemListingType(DjangoObjectType): + class Meta: + model = ItemListing + fields = ("item_name", "price", "amount", "date_restocked", "normalized_price", "id") + + normalized_price = graphene.Float() + + +class ResourceType(DjangoObjectType): + class Meta: + model = Resource + fields = ("resource_name", "id") + + +class LocationType(DjangoObjectType): + class Meta: + model = Location + fields = ("id", "name", "loc_type", "x_coord", "z_coord", "dimension", "owner", "tunnel", "link") + + loc_type = graphene.String() + owner = graphene.List(PlayerType) + link = graphene.String() + tunnel = graphene.Field(TunnelType) + + def resolve_owner(self, info): + return self.owner.all() + + +class ShopType(LocationType): + class Meta: + model = Shop + + inventory = graphene.List(ItemListingType) + + def resolve_inventory(self, info): + return self.shop_selling.all() + + +class PublicFarmType(LocationType): + class Meta: + model = PublicFarm + + resource = graphene.List(ResourceType) + + def resolve_resource(self, info): + return self.resource.all() + + +class BaseType(LocationType): + class Meta: + model = Base + + +class PointOfInterestType(LocationType): + class Meta: + model = PointOfInterest + + +class MarketType(LocationType): + class Meta: + model = Market + + shops = graphene.List(ShopType) + + def resolve_shops(self, info): + return self.get_shops() + + +class AttractionType(LocationType): + class Meta: + model = Attraction + + +class TownType(LocationType): + class Meta: + model = Attraction + + residents = graphene.List(PlayerType) + + def resolve_residents(self, info): + return self.residents.all() + + +class ProtectedAPI(): + def __init__(self, func): + self.func = func + + @staticmethod + def protected_api(): + def wrapper(func): + return ProtectedAPI(func) + + return wrapper + + def __call__(self, root, info, **kwargs): + if "X-GeoffreyAPI-Token" in info.context.headers: + token = info.context.headers["X-GeoffreyAPI-Token"] + elif "token" in info.context.GET: + token = info.context.GET["token"] + else: + raise UnauthorizedQuery + + if check_key(token, model_api_perm=True): + return self.func(root, info, **kwargs) + else: + return UnauthorizedQuery + + +class Query(graphene.ObjectType): + player = graphene.Field(PlayerType, id=graphene.Argument(graphene.Int, required=False), name=graphene.Argument(graphene.String, required=False), discord_uuid=graphene.Argument(graphene.String, required=False)) + locations = graphene.List(LocationType, id=graphene.Argument(graphene.Int, required=False), name=graphene.Argument(graphene.String, required=False)) + shops = graphene.List(ShopType, id=graphene.Argument(graphene.Int, required=False), name=graphene.Argument(graphene.String, required=False)) + towns = graphene.List(TownType, id=graphene.Argument(graphene.Int, required=False), name=graphene.Argument(graphene.String, required=False)) + farms = graphene.List(PublicFarmType, id=graphene.Argument(graphene.Int, required=False), name=graphene.Argument(graphene.String, required=False)) + bases = graphene.List(BaseType, id=graphene.Argument(graphene.Int, required=False), name=graphene.Argument(graphene.String, required=False)) + attractions = graphene.List(AttractionType, id=graphene.Argument(graphene.Int, required=False), name=graphene.Argument(graphene.String, required=False)) + points_of_interest = graphene.List(PointOfInterestType, id=graphene.Argument(graphene.Int, required=False), name=graphene.Argument(graphene.String, required=False)) + + @ProtectedAPI.protected_api() + def resolve_player(root, info, id, name, discord_uuid, mc_uuid): + return Player.objects.get(pk=id, name=name, discord_uuid=discord_uuid, mc_uuid=mc_uuid) + + @ProtectedAPI.protected_api() + def resolve_locations(root, info, id=None, name=None): + return get_location(root, info, id=id, name=name, location_type=Location) + + @ProtectedAPI.protected_api() + def resolve_shops(root, info, id=None, name=None): + return get_location(root, info, id=id, name=name, location_type=Shop) + + @ProtectedAPI.protected_api() + def resolved_towns(root, info, id=None, name=None): + return get_location(root, info, id=id, name=name, location_type=Town) + + @ProtectedAPI.protected_api() + def resolved_farms(root, info, id=None, name=None): + return get_location(root, info, id=id, name=name, location_type=PublicFarm) + + @ProtectedAPI.protected_api() + def resolved_bases(root, info, id=None, name=None): + return get_location(root, info, id=id, name=name, location_type=Base) + + @ProtectedAPI.protected_api() + def resolved_attractions(root, info, id=None, name=None): + return get_location(root, info, id=id, name=name, location_type=Attraction) + + @ProtectedAPI.protected_api() + def resolved_points_of_interest(root, info, id=None, name=None): + return get_location(root, info, id=id, name=name, location_type=PointOfInterest) + + +def get_location(root, info, id=None, name=None, location_type=Location): + if id is not None: + return location_type.objects.get(pk=id) + elif name is not None: + return location_type.objects.get(name__icontains=name) + else: + return location_type.objects.all() + + +schema = graphene.Schema(query=Query) diff --git a/setup.py b/setup.py index d578770..9c86192 100644 --- a/setup.py +++ b/setup.py @@ -18,5 +18,5 @@ setup( url='https:/geoffrey.zerohighdef.com/', author='ZeroHD', author_email='zero@zerohighdef.com', - install_requires=['django', 'requests', 'simplejson'] + install_requires=['django', 'requests', 'simplejson', 'graphene_django'] )