Skip to content

Commit

Permalink
First pass implementation of graphql schema in server for metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
npalaska committed Dec 17, 2020
1 parent ca4877c commit faf6c5a
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 5 deletions.
13 changes: 11 additions & 2 deletions lib/pbench/server/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

import os

from flask import Flask
from flask import Flask, request
from flask_restful import Api
from flask_cors import CORS

from pbench.server import PbenchServerConfig
from pbench.common.exceptions import BadConfig, ConfigFileNotSpecified
from pbench.server.api.resources.upload_api import Upload, HostInfo
from pbench.server.api.resources.graphql_api import GraphQL
from pbench.server.api.resources.graphql_api import GraphQL, UserMetadata
from pbench.common.logger import get_pbench_logger
from pbench.server.api.resources.query_apis.elasticsearch_api import Elasticsearch
from pbench.server.api.resources.query_apis.query_controllers import QueryControllers
Expand Down Expand Up @@ -74,6 +74,10 @@ def register_endpoints(api, app, config):
UserAPI, f"{base_uri}/user/<string:username>", resource_class_args=(logger,),
)

api.add_resource(
UserMetadata, f"{base_uri}/user/metadata", resource_class_args=(config, logger),
)


def get_server_config():
cfg_name = os.environ.get("_PBENCH_SERVER_CONFIG")
Expand Down Expand Up @@ -107,6 +111,11 @@ def create_app(server_config):

Database.init_db(server_config=server_config, logger=app.logger)

@app.before_request
def before_request():
print(request.path)
print(request.remote_addr)

@app.teardown_appcontext
def shutdown_session(exception=None):
Database.db_session.remove()
Expand Down
83 changes: 82 additions & 1 deletion lib/pbench/server/api/resources/graphql_api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,87 @@
import requests
from flask_restful import Resource, abort
from flask import request, make_response
from flask import request, make_response, jsonify
from pbench.server.api.resources.auth import auth
from pbench.server.api.resources.graphql_schema import schema


class UserMetadata(Resource):
"""
Abstracted pbench API for handling user metadata by using graphql schema
"""

def __init__(self, config, logger):
self.server_config = config
self.logger = logger

@auth.login_required()
def post(self):
"""
Post request for creating metadata instance for a user.
This requires a JWT auth token in the header field
This requires a JSON data with required user metadata fields
{
"config": "config",
"description": "description",
}
Required headers include
Authorization: JWT token (user received upon login)
:return: JSON Payload
response_object = {
"status": "success"
"data" {
"id": "metadata_id",
"config": "Config string"
"description": "Description string"
}
}
"""
post_data = request.get_json()
if not post_data:
self.logger.warning("Invalid json object: %s", request.url)
abort(400, message="Invalid json object in request")

config = post_data.get("config")
if not config:
self.logger.warning("Config not provided during metadata creation")
abort(400, message="Please provide a config string")

description = post_data.get("description")
if not description:
self.logger.warning("Description not provided during metadata creation")
abort(400, message="Please provide a description string")
current_user_id = auth.current_user().id
try:
# query GraphQL
query = f"""
mutation {{
createMetadata (input: {{config:"{config}", description:"{description}", user_id:{current_user_id}}}) {{
metadata {{
id
config
description
}}
}}
}}
"""
result = schema.execute(query)
except Exception as e:
self.logger.exception("Exception occurred during Metadata creation")
abort(500, message="INTERNAL ERROR")
else:
data = result.data["createMetadata"]["metadata"]
response_object = {
"status": "success",
"data": {
"id": data["id"],
"config": data["config"],
"description": data["description"],
},
}
return make_response(jsonify(response_object), 201)


class GraphQL(Resource):
Expand Down
74 changes: 74 additions & 0 deletions lib/pbench/server/api/resources/graphql_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from pbench.server.api.resources.models import MetadataModel
from pbench.server.api.resources.database import Database

import graphene
from graphene import relay
from graphene_sqlalchemy import SQLAlchemyObjectType


# Define graphql types
class Metadata(SQLAlchemyObjectType):
class Meta:
model = MetadataModel
interfaces = (relay.Node,)


class MetadataAttribute:
id = graphene.ID
user_id = graphene.ID()
created = graphene.DateTime()
updated = graphene.DateTime()
config = graphene.String()
description = graphene.String()


class CreateMetadataInput(graphene.InputObjectType, MetadataAttribute):
pass


# mutations
class CreateMetadata(graphene.Mutation):
metadata = graphene.Field(lambda: Metadata)
ok = graphene.Boolean()

class Arguments:
input = CreateMetadataInput(required=True)

@staticmethod
def mutate(self, info, input):
data = input
metadata = MetadataModel(**data)
Database.db_session.add(metadata)
Database.db_session.commit()
ok = True
return CreateMetadata(metadata=metadata, ok=ok)


class Mutation(graphene.ObjectType):
createMetadata = CreateMetadata.Field()


# Query
class Query(graphene.ObjectType):
node = relay.Node.Field()

metadata_by_id = graphene.List(Metadata, id=graphene.String())
metadata_by_userid = graphene.List(Metadata, userid=graphene.String())

@staticmethod
def resolve_metadata_by_id(parent, info, **args):
q = args.get("id")

metadata_query = Metadata.get_query(info)
return metadata_query.filter(MetadataModel.id == q).all()

@staticmethod
def resolve_metadata_by_userid(parent, info, **args):
q = args.get("userid")

metadata_query = Metadata.get_query(info)
return metadata_query.filter(MetadataModel.user_id == q).all()


# schema
schema = graphene.Schema(query=Query, mutation=Mutation, types=[Metadata])
7 changes: 5 additions & 2 deletions lib/pbench/server/api/resources/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class UserModel(Database.Base):
registered_on = Column(DateTime, nullable=False)
email = Column(String(255), unique=True, nullable=False)
auth_tokens = relationship("ActiveTokens", backref="users")
user_metadata = relationship("MetadataModel", uselist=False, backref="users")

def __init__(self, bcrypt_log_rounds, **kwargs):
super().__init__(**kwargs)
Expand Down Expand Up @@ -76,7 +77,7 @@ def valid(auth_token):
return False


class Metadata(Database.Base):
class MetadataModel(Database.Base):
""" Metadata Model for storing user metadata details """

# TODO: Think about the better name
Expand All @@ -87,12 +88,14 @@ class Metadata(Database.Base):
updated = Column(DateTime, nullable=False)
config = Column(String(255), unique=False, nullable=False)
description = Column(String(255), nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))

def __init__(self, created, config, description):
def __init__(self, created, config, description, user_id):
self.created = parser.parse(created)
self.updated = datetime.datetime.now()
self.config = config
self.description = description
self.user_id = user_id

def __str__(self):
return f"Url id: {self.id}, created on: {self.created}, description: {self.description}"

0 comments on commit faf6c5a

Please sign in to comment.