Adicionar 2 rotas
This commit is contained in:
@@ -16,3 +16,9 @@ def ConflictingResources(message):
|
||||
|
||||
def AuthenticationFailure(message):
|
||||
return error(4, "AuthenticationFailure", message, http_code=401)
|
||||
|
||||
def ForbiddenError(message):
|
||||
return error(5, "ForbiddenError", message, http_code=403)
|
||||
|
||||
def FetchError(message):
|
||||
return error(6, "FetchError", message, http_code=500)
|
||||
|
65
api/views/helper.py
Normal file
65
api/views/helper.py
Normal file
@@ -0,0 +1,65 @@
|
||||
from functools import wraps
|
||||
from flask import request
|
||||
from api.models.trainer import Trainer
|
||||
from .errors import AuthenticationFailure
|
||||
from api.app import app
|
||||
import requests
|
||||
import json
|
||||
import jwt
|
||||
|
||||
class HTTPError(Exception):
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
class TrainerNotFound(Exception):
|
||||
pass
|
||||
|
||||
def get_trainer_fail(id):
|
||||
try:
|
||||
trainer = Trainer.query.get(id)
|
||||
if trainer is None:
|
||||
raise TrainerNotFound()
|
||||
return trainer
|
||||
except:
|
||||
raise TrainerNotFound()
|
||||
|
||||
def get_trainer_by_nick_fail(nickname):
|
||||
try:
|
||||
trainer = Trainer.query.filter_by(nickname=nickname).one()
|
||||
if trainer is None:
|
||||
raise TrainerNotFound()
|
||||
return trainer
|
||||
except:
|
||||
raise TrainerNotFound()
|
||||
|
||||
# authenticação do trainer (decorator)
|
||||
def token_required(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
try:
|
||||
token = request.headers["authorization"]
|
||||
print(token)
|
||||
print(app.config["SECRET_KEY"])
|
||||
data = jwt.decode(token, app.config["SECRET_KEY"], algorithms=["HS256"])
|
||||
print(data["username"])
|
||||
trainer = get_trainer_by_nick_fail(data["username"])
|
||||
except (TypeError, KeyError):
|
||||
return AuthenticationFailure("JWT token required")
|
||||
except:
|
||||
return AuthenticationFailure("JWT token is invalid or expired")
|
||||
|
||||
return f(trainer, *args, **kwargs)
|
||||
return decorated
|
||||
|
||||
# seguintes funções puxam informações da pokeapi
|
||||
def set_pokemon_data(pokemon):
|
||||
response = requests.get("https://pokeapi.co/api/v2/pokemon/{}".format(pokemon.pokemon_id))
|
||||
if response.status_code != 200:
|
||||
raise HTTPError("Could not fetch pokemon with id {}".format(pokemon.pokemon_id))
|
||||
pokemon.pokemon_data = json.loads(response.text)
|
||||
|
||||
async def async_set_pokemon_data(session, pokemon):
|
||||
response = await session.get("https://pokeapi.co/api/v2/pokemon/{}".format(pokemon.pokemon_id))
|
||||
if response.status != 200:
|
||||
raise HTTPError("Could not fetch pokemon with id {}".format(pokemon.pokemon_id))
|
||||
pokemon.pokemon_data = json.loads(await response.text())
|
33
api/views/parse_args.py
Normal file
33
api/views/parse_args.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from flask import request
|
||||
|
||||
class ParsingException(Exception):
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def parse_int(name, minimum):
|
||||
try:
|
||||
result = int(request.args.get(name, minimum))
|
||||
except ValueError:
|
||||
raise ParsingException("Couldn't parse {} as integer".format(name))
|
||||
|
||||
if result < minimum:
|
||||
raise ParsingException("{} must be greater than {}".format(name, minimum))
|
||||
|
||||
return result
|
||||
|
||||
def parse_limit():
|
||||
return parse_int("limit", -1)
|
||||
|
||||
def parse_offset():
|
||||
return parse_int("offset", 0)
|
||||
|
||||
def parse_json_obj():
|
||||
try:
|
||||
json = request.get_json()
|
||||
except:
|
||||
raise ParsingException("Failed to parse JSON body")
|
||||
|
||||
if type(json) is not dict:
|
||||
raise ParsingException("Expected JSON object as body")
|
||||
|
||||
return json
|
64
api/views/pokemon_owned.py
Normal file
64
api/views/pokemon_owned.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from api.models.pokemon_owned import pokemon_owned_schema, pokemon_owned_schemas, PokemonOwned
|
||||
from api.app import db
|
||||
from .parse_args import parse_limit, parse_offset, ParsingException, parse_json_obj
|
||||
from .errors import ParsingError, FetchError, ConflictingResources
|
||||
from .helper import TrainerNotFound, HTTPError, get_trainer_fail, set_pokemon_data, async_set_pokemon_data
|
||||
from aiohttp import ClientSession
|
||||
from asyncio import create_task, gather
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
def post_pokemon_owned(trainer_id):
|
||||
try:
|
||||
json = parse_json_obj()
|
||||
pokemon_id = json["pokemon_id"]
|
||||
name = json["name"]
|
||||
level = json["level"]
|
||||
except ParsingException as e:
|
||||
return ParsingError(e.message)
|
||||
except KeyError:
|
||||
return ParsingError("Missing JSON object fields")
|
||||
|
||||
pokemon = PokemonOwned(
|
||||
name=name,
|
||||
level=level,
|
||||
pokemon_id=pokemon_id,
|
||||
trainer_id=trainer_id
|
||||
)
|
||||
|
||||
try:
|
||||
set_pokemon_data(pokemon)
|
||||
|
||||
db.session.add(pokemon)
|
||||
db.session.commit()
|
||||
except HTTPError as e:
|
||||
return FetchError(e.message)
|
||||
except IntegrityError:
|
||||
return ConflictingResources("Trainer already has another pokemon with the same name")
|
||||
|
||||
return (pokemon_owned_schema.dump(pokemon), 201)
|
||||
|
||||
async def get_pokemons_owned(trainer_id):
|
||||
try:
|
||||
limit = parse_limit()
|
||||
offset = parse_offset()
|
||||
except ParsingException as e:
|
||||
return ParsingError(e.message)
|
||||
|
||||
try:
|
||||
trainer = get_trainer_fail(trainer_id)
|
||||
except TrainerNotFound:
|
||||
return "", 404
|
||||
|
||||
pokemons = trainer.pokemons_list.limit(limit).offset(offset).all()
|
||||
|
||||
async with ClientSession() as session:
|
||||
tasks = []
|
||||
for pokemon in pokemons:
|
||||
task = create_task(async_set_pokemon_data(session, pokemon))
|
||||
tasks.append(task)
|
||||
try:
|
||||
await gather(*tasks)
|
||||
except HTTPError as e:
|
||||
return FetchError(e.message)
|
||||
|
||||
return pokemon_owned_schemas.dumps(pokemons)
|
@@ -3,7 +3,8 @@ from api.models.trainer import Trainer, trainer_schema, trainer_schemas, Invalid
|
||||
from api.app import db
|
||||
from api.app import app
|
||||
from flask import request, jsonify
|
||||
from .errors import ParsingError, ConflictingParameters, ConflictingResources, AuthenticationFailure
|
||||
from .errors import *
|
||||
from .parse_args import parse_limit, parse_offset, ParsingException, parse_json_obj
|
||||
from werkzeug.security import check_password_hash
|
||||
import datetime
|
||||
import jwt
|
||||
@@ -12,19 +13,16 @@ def get_trainer(id):
|
||||
try:
|
||||
return trainer_schema.dump(Trainer.query.get(id))
|
||||
except:
|
||||
return jsonify({})
|
||||
return ("", 404)
|
||||
|
||||
def get_trainers():
|
||||
args = request.args
|
||||
|
||||
try:
|
||||
limit = int(args.get("limit", -1))
|
||||
offset = int(args.get("offset", 0))
|
||||
except ValueError:
|
||||
return ParsingError("Couldn't parse parameter as integer")
|
||||
|
||||
if limit < -1 or offset < 0:
|
||||
return ParsingError("Expected positive integer as parameter")
|
||||
limit = parse_limit()
|
||||
offset = parse_offset()
|
||||
except ParsingException as e:
|
||||
return ParsingError(e.message)
|
||||
|
||||
nickname = args.get("nickname", "")
|
||||
nickname_contains = args.get("nickname_contains", "")
|
||||
@@ -53,14 +51,8 @@ def get_trainer_by_email(email):
|
||||
|
||||
def post_trainer():
|
||||
try:
|
||||
json = request.get_json()
|
||||
except:
|
||||
return ParsingError("Failed to parse JSON body")
|
||||
json = parse_json_obj()
|
||||
|
||||
if type(json) is not dict:
|
||||
return ParsingError("Expected JSON object as body")
|
||||
|
||||
try:
|
||||
nickname = json["nickname"]
|
||||
first_name = json["first_name"]
|
||||
last_name = json["last_name"]
|
||||
@@ -81,25 +73,22 @@ def post_trainer():
|
||||
db.session.commit()
|
||||
|
||||
return trainer_schema.dump(trainer)
|
||||
except ParsingException as e:
|
||||
return ParsingError(e.message)
|
||||
except InvalidTeam:
|
||||
return ParsingError("Field team is invalid")
|
||||
except KeyError:
|
||||
return ParsingError("Missing JSON object fields")
|
||||
except IntegrityError:
|
||||
return ConflictingResources("Trainer with the same nickname or email already exists", http_code=500)
|
||||
return ConflictingResources("Trainer with the same nickname or email already exists")
|
||||
|
||||
def auth_trainer():
|
||||
try:
|
||||
auth = request.get_json()
|
||||
except:
|
||||
return ParsingError("Failed to parse JSON body")
|
||||
|
||||
if type(auth) is not dict:
|
||||
return ParsingError("Expected JSON object as body")
|
||||
|
||||
try:
|
||||
auth = parse_json_obj()
|
||||
email = auth["email"]
|
||||
password = auth["password"]
|
||||
except ParsingException as e:
|
||||
return ParsingError(e.message)
|
||||
except KeyError:
|
||||
return AuthenticationFailure("Login required")
|
||||
|
||||
@@ -113,7 +102,7 @@ def auth_trainer():
|
||||
"username": trainer.nickname,
|
||||
"exp": datetime.datetime.now() + datetime.timedelta(hours=12)
|
||||
},
|
||||
app.config["SECRET_KEY"])
|
||||
app.config["SECRET_KEY"], algorithm="HS256")
|
||||
return jsonify(
|
||||
{
|
||||
"id": trainer.id,
|
||||
|
Reference in New Issue
Block a user