Add pitchercards and ratings
This commit is contained in:
parent
22cc01d200
commit
51a5251c92
@ -556,7 +556,8 @@ class BattingCard(BaseModel):
|
||||
hand = CharField(default='R')
|
||||
|
||||
|
||||
BattingCard.add_index(BattingCard.player, BattingCard.variant)
|
||||
bc_index = ModelIndex(BattingCard, (BattingCard.player, BattingCard.variant), unique=True)
|
||||
BattingCard.add_index(bc_index)
|
||||
|
||||
|
||||
class BattingCardRatings(BaseModel):
|
||||
@ -589,22 +590,26 @@ class BattingCardRatings(BaseModel):
|
||||
slg = FloatField(null=True)
|
||||
|
||||
|
||||
BattingCardRatings.add_index(BattingCardRatings.battingcard, BattingCardRatings.vs_hand)
|
||||
bcr_index = ModelIndex(BattingCardRatings, (BattingCardRatings.battingcard, BattingCardRatings.vs_hand), unique=True)
|
||||
BattingCardRatings.add_index(bcr_index)
|
||||
|
||||
|
||||
class PitchingCard(BaseModel):
|
||||
player = ForeignKeyField(Player)
|
||||
variant = IntegerField()
|
||||
balk = IntegerField()
|
||||
wild_pitch = IntegerField(null=True)
|
||||
hold = CharField()
|
||||
wild_pitch = IntegerField()
|
||||
hold = IntegerField()
|
||||
starter_rating = IntegerField()
|
||||
relief_rating = IntegerField()
|
||||
closer_rating = IntegerField(null=True)
|
||||
batting = CharField(null=True)
|
||||
offense_col = IntegerField()
|
||||
hand = CharField(default='R')
|
||||
|
||||
|
||||
PitchingCard.add_index(PitchingCard.player, PitchingCard.variant)
|
||||
pc_index = ModelIndex(PitchingCard, (PitchingCard.player, PitchingCard.variant), unique=True)
|
||||
PitchingCard.add_index(bc_index)
|
||||
|
||||
|
||||
class PitchingCardRatings(BaseModel):
|
||||
@ -641,6 +646,10 @@ class PitchingCardRatings(BaseModel):
|
||||
slg = FloatField(null=True)
|
||||
|
||||
|
||||
pcr_index = ModelIndex(PitchingCardRatings, (PitchingCardRatings.pitchingcard, PitchingCardRatings.vs_hand), unique=True)
|
||||
PitchingCardRatings.add_index(pcr_index)
|
||||
|
||||
|
||||
class CardPosition(BaseModel):
|
||||
player = ForeignKeyField(Player)
|
||||
batting = ForeignKeyField(BattingCard, null=True)
|
||||
|
||||
@ -3,7 +3,7 @@ from fastapi import FastAPI
|
||||
from.routers_v2 import (
|
||||
current, teams, rarity, cardsets, players, packtypes, packs, cards, events, results, rewards,
|
||||
batstats, pitstats, notifications, paperdex, gamerewards, gauntletrewards, gauntletruns, battingcards,
|
||||
battingcardratings)
|
||||
battingcardratings, pitchingcards, pitchingcardratings)
|
||||
|
||||
app = FastAPI(
|
||||
responses={404: {'description': 'Not found'}}
|
||||
@ -29,3 +29,5 @@ app.include_router(gauntletrewards.router)
|
||||
app.include_router(gauntletruns.router)
|
||||
app.include_router(battingcards.router)
|
||||
app.include_router(battingcardratings.router)
|
||||
app.include_router(pitchingcards.router)
|
||||
app.include_router(pitchingcardratings.router)
|
||||
|
||||
@ -110,7 +110,15 @@ async def get_card_ratings(
|
||||
|
||||
|
||||
@router.get('/{ratings_id}')
|
||||
async def get_one_rating(ratings_id: int):
|
||||
async def get_one_rating(ratings_id: int, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail='You are not authorized to pull card ratings.'
|
||||
)
|
||||
|
||||
this_rating = BattingCardRatings.get_or_none(BattingCardRatings.id == ratings_id)
|
||||
if this_rating is None:
|
||||
db.close()
|
||||
@ -121,7 +129,7 @@ async def get_one_rating(ratings_id: int):
|
||||
return r_data
|
||||
|
||||
|
||||
@router.get('')
|
||||
@router.get('/{player_id}')
|
||||
async def get_player_ratings(player_id: int, variant: list = Query(default=None), short_output: bool = False):
|
||||
all_cards = BattingCard.select().where(BattingCard.player_id == player_id).order_by(BattingCard.variant)
|
||||
if variant is not None:
|
||||
@ -157,7 +165,7 @@ async def put_ratings(ratings: RatingsList, token: str = Depends(oauth2_scheme))
|
||||
|
||||
@router.delete('/{ratings_id}')
|
||||
async def put_one_rating(
|
||||
ratings_id: int, this_rating: BattingCardRatingsModel, token: str = Depends(oauth2_scheme)):
|
||||
ratings_id: int, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
|
||||
@ -140,6 +140,7 @@ async def patch_card(
|
||||
db.close()
|
||||
return return_val
|
||||
else:
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=418,
|
||||
detail='Well slap my ass and call me a teapot; I could not save that card'
|
||||
|
||||
194
app/routers_v2/pitchingcardratings.py
Normal file
194
app/routers_v2/pitchingcardratings.py
Normal file
@ -0,0 +1,194 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from typing import Literal, Optional, List
|
||||
import logging
|
||||
import pydantic
|
||||
from pydantic import validator, root_validator
|
||||
|
||||
from ..db_engine import db, PitchingCardRatings, model_to_dict, chunked, PitchingCard
|
||||
from ..dependencies import oauth2_scheme, valid_token, LOG_DATA
|
||||
|
||||
logging.basicConfig(
|
||||
filename=LOG_DATA['filename'],
|
||||
format=LOG_DATA['format'],
|
||||
level=LOG_DATA['log_level']
|
||||
)
|
||||
|
||||
router = APIRouter(
|
||||
prefix='/api/v2/pitchingcardratings',
|
||||
tags=['pitchingcardratings']
|
||||
)
|
||||
|
||||
|
||||
class PitchingCardRatingsModel(pydantic.BaseModel):
|
||||
pitchingcard_id: int
|
||||
vs_hand: Literal['R', 'L', 'vR', 'vL']
|
||||
homerun: float = 0.0
|
||||
bp_homerun: float = 0.0
|
||||
triple: float = 0.0
|
||||
double_three: float = 0.0
|
||||
double_two: float = 0.0
|
||||
double_cf: float = 0.0
|
||||
single_two: float = 0.0
|
||||
single_one: float = 0.0
|
||||
single_center: float = 0.0
|
||||
bp_single: float = 0.0
|
||||
hbp: float = 0.0
|
||||
walk: float = 0.0
|
||||
strikeout: float = 0.0
|
||||
fo_slap: float = 0.0
|
||||
fo_center: float = 0.0
|
||||
groundout_a: float = 0.0
|
||||
groundout_b: float = 0.0
|
||||
xcheck_p: float = 0.0
|
||||
xcheck_c: float = 0.0
|
||||
xcheck_1b: float = 0.0
|
||||
xcheck_2b: float = 0.0
|
||||
xcheck_3b: float = 0.0
|
||||
xcheck_ss: float = 0.0
|
||||
xcheck_lf: float = 0.0
|
||||
xcheck_cf: float = 0.0
|
||||
xcheck_rf: float = 0.0
|
||||
avg: float = 0.0
|
||||
obp: float = 0.0
|
||||
slg: float = 0.0
|
||||
|
||||
@validator("avg", always=True)
|
||||
def avg_validator(cls, v, values, **kwargs):
|
||||
return (values['homerun'] + values['bp_homerun'] / 2 + values['triple'] + values['double_three'] +
|
||||
values['double_two'] + values['double_cf'] + values['single_two'] + values['single_one'] +
|
||||
values['single_center'] + values['bp_single'] / 2) / 108
|
||||
|
||||
@validator("obp", always=True)
|
||||
def obp_validator(cls, v, values, **kwargs):
|
||||
return ((values['hbp'] + values['walk']) / 108) + values['avg']
|
||||
|
||||
@validator("slg", always=True)
|
||||
def slg_validator(cls, v, values, **kwargs):
|
||||
return (values['homerun'] * 4 + values['bp_homerun'] * 2 + values['triple'] * 3 + values['double_three'] * 2 +
|
||||
values['double_two'] * 2 + values['double_cf'] * 2 + values['single_two'] + values['single_one'] +
|
||||
values['single_center'] + values['bp_single'] / 2) / 108
|
||||
|
||||
@root_validator
|
||||
def validate_chance_total(cls, values):
|
||||
total_chances = (
|
||||
values['homerun'] + values['bp_homerun'] + values['triple'] + values['double_three'] +
|
||||
values['double_two'] + values['double_cf'] + values['single_two'] + values['single_one'] +
|
||||
values['single_center'] + values['bp_single'] + values['hbp'] + values['walk'] +
|
||||
values['strikeout'] + values['fo_slap'] + values['fo_center'] + values['groundout_a'] +
|
||||
values['groundout_b'] + values['xcheck_p'] + values['xcheck_c'] + values['xcheck_1b'] +
|
||||
values['xcheck_2b'] + values['xcheck_3b'] + values['xcheck_ss'] + values['xcheck_lf'] +
|
||||
values['xcheck_cf'] + values['xcheck_rf'])
|
||||
|
||||
if total_chances != 108:
|
||||
raise ValueError("Must have exactly 108 chances on the card")
|
||||
return values
|
||||
|
||||
|
||||
class RatingsList(pydantic.BaseModel):
|
||||
ratings: List[PitchingCardRatingsModel]
|
||||
|
||||
|
||||
@router.get('')
|
||||
async def get_card_ratings(
|
||||
pitchingcard_id: list = Query(default=None), vs_hand: Literal['R', 'L', 'vR', 'vL'] = None,
|
||||
short_output: bool = False, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail='You are not authorized to pull card ratings.'
|
||||
)
|
||||
|
||||
all_ratings = PitchingCardRatings.select()
|
||||
|
||||
if pitchingcard_id is not None:
|
||||
all_ratings = all_ratings.where(PitchingCardRatings.pitchingcard_id << pitchingcard_id)
|
||||
if vs_hand is not None:
|
||||
all_ratings = all_ratings.where(PitchingCardRatings.vs_hand << vs_hand[-1])
|
||||
|
||||
return_val = {'count': all_ratings.count(), 'ratings': [
|
||||
model_to_dict(x, recurse=not short_output) for x in all_ratings
|
||||
]}
|
||||
db.close()
|
||||
return return_val
|
||||
|
||||
|
||||
@router.get('/{ratings_id}')
|
||||
async def get_one_rating(ratings_id: int, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail='You are not authorized to pull card ratings.'
|
||||
)
|
||||
|
||||
this_rating = PitchingCardRatings.get_or_none(PitchingCardRatings.id == ratings_id)
|
||||
if this_rating is None:
|
||||
db.close()
|
||||
raise HTTPException(status_code=404, detail=f'PitchingCardRating id {ratings_id} not found')
|
||||
|
||||
r_data = model_to_dict(this_rating)
|
||||
db.close()
|
||||
return r_data
|
||||
|
||||
|
||||
@router.get('/{player_id}')
|
||||
async def get_player_ratings(player_id: int, variant: list = Query(default=None), short_output: bool = False):
|
||||
all_cards = PitchingCard.select().where(PitchingCard.player_id == player_id).order_by(PitchingCard.variant)
|
||||
if variant is not None:
|
||||
all_cards = all_cards.where(PitchingCard.variant << variant)
|
||||
|
||||
all_ratings = PitchingCardRatings.select().where(PitchingCardRatings.PitchingCard << all_cards)
|
||||
|
||||
return_val = {'count': all_ratings.count(), 'ratings': [
|
||||
model_to_dict(x, recurse=not short_output) for x in all_ratings
|
||||
]}
|
||||
db.close()
|
||||
return return_val
|
||||
|
||||
|
||||
@router.put('')
|
||||
async def put_ratings(ratings: RatingsList, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail='You are not authorized to post card ratings.'
|
||||
)
|
||||
|
||||
new_ratings = [x.dict() for x in ratings.ratings]
|
||||
with db.atomic():
|
||||
for batch in chunked(new_ratings, 30):
|
||||
PitchingCardRatings.insert_many(batch).on_conflict_replace().execute() # TODO: replace gives new ID which breaks links
|
||||
|
||||
db.close()
|
||||
return f'Inserted {len(new_ratings)} batting ratings'
|
||||
|
||||
|
||||
@router.delete('/{ratings_id}')
|
||||
async def put_one_rating(
|
||||
ratings_id: int, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail='You are not authorized to post card ratings.'
|
||||
)
|
||||
|
||||
this_rating = PitchingCardRatings.get_or_none(PitchingCardRatings.id == ratings_id)
|
||||
if this_rating is None:
|
||||
db.close()
|
||||
raise HTTPException(status_code=404, detail=f'PitchingCardRating id {ratings_id} not found')
|
||||
|
||||
count = this_rating.delete_instance()
|
||||
db.close()
|
||||
|
||||
if count == 1:
|
||||
return f'Rating {this_rating} has been deleted'
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail=f'Rating {this_rating} could not be deleted')
|
||||
|
||||
166
app/routers_v2/pitchingcards.py
Normal file
166
app/routers_v2/pitchingcards.py
Normal file
@ -0,0 +1,166 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from typing import Literal, Optional, List
|
||||
import logging
|
||||
import pydantic
|
||||
|
||||
from ..db_engine import db, PitchingCard, model_to_dict, chunked, Player
|
||||
from ..dependencies import oauth2_scheme, valid_token, LOG_DATA
|
||||
|
||||
logging.basicConfig(
|
||||
filename=LOG_DATA['filename'],
|
||||
format=LOG_DATA['format'],
|
||||
level=LOG_DATA['log_level']
|
||||
)
|
||||
|
||||
router = APIRouter(
|
||||
prefix='/api/v2/pitchingcards',
|
||||
tags=['pitchingcards']
|
||||
)
|
||||
|
||||
|
||||
class PitchingCardModel(pydantic.BaseModel):
|
||||
player_id: int
|
||||
variant: int = 0
|
||||
balk: int = 0
|
||||
wild_pitch: int = 0
|
||||
hold: int = 0
|
||||
starter_rating: int = 1
|
||||
relief_rating: int = 0
|
||||
closer_rating: int = None
|
||||
batting: str = "#1WR-C"
|
||||
offense_col: int
|
||||
hand: Literal['R', 'L', 'S'] = 'R'
|
||||
|
||||
|
||||
class PitchingCardList(pydantic.BaseModel):
|
||||
cards: List[PitchingCardModel]
|
||||
|
||||
|
||||
@router.get('')
|
||||
async def get_pitching_cards(
|
||||
player_id: list = Query(default=None), cardset_id: list = Query(default=None), short_output: bool = False):
|
||||
all_cards = PitchingCard.select()
|
||||
if player_id is not None:
|
||||
all_cards = all_cards.where(PitchingCard.player_id << player_id)
|
||||
if cardset_id is not None:
|
||||
all_players = Player.select().where(Player.cardset_id << cardset_id)
|
||||
all_cards = all_cards.where(PitchingCard.player << all_players)
|
||||
|
||||
return_val = {'count': all_cards.count(), 'cards': [
|
||||
model_to_dict(x, recurse=not short_output) for x in all_cards
|
||||
]}
|
||||
db.close()
|
||||
return return_val
|
||||
|
||||
|
||||
@router.get('/{card_id}')
|
||||
async def get_one_card(card_id: int):
|
||||
this_card = PitchingCard.get_or_none(PitchingCard.id == card_id)
|
||||
if this_card is None:
|
||||
db.close()
|
||||
raise HTTPException(status_code=404, detail=f'PitchingCard id {card_id} not found')
|
||||
|
||||
r_card = model_to_dict(this_card)
|
||||
db.close()
|
||||
return r_card
|
||||
|
||||
|
||||
@router.get('/player/{player_id}')
|
||||
async def get_player_cards(player_id: int, variant: list = Query(default=None), short_output: bool = False):
|
||||
all_cards = PitchingCard.select().where(PitchingCard.player_id == player_id).order_by(PitchingCard.variant)
|
||||
if variant is not None:
|
||||
all_cards = all_cards.where(PitchingCard.variant << variant)
|
||||
|
||||
return_val = {'count': all_cards.count(), 'cards': [
|
||||
model_to_dict(x, recurse=not short_output) for x in all_cards
|
||||
]}
|
||||
db.close()
|
||||
return return_val
|
||||
|
||||
|
||||
@router.put('')
|
||||
async def put_cards(cards: PitchingCardList, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail='You are not authorized to post batting cards. This event has been logged.'
|
||||
)
|
||||
|
||||
new_cards = [x.dict() for x in cards.cards]
|
||||
with db.atomic():
|
||||
for batch in chunked(new_cards, 30):
|
||||
PitchingCard.insert_many(batch).on_conflict_replace().execute()
|
||||
|
||||
db.close()
|
||||
return f'Inserted {len(new_cards)} batting cards'
|
||||
|
||||
|
||||
@router.patch('/{card_id}')
|
||||
async def patch_card(
|
||||
card_id: int, balk: Optional[int] = None, wild_pitch: Optional[int] = None, hold: Optional[int] = None,
|
||||
starter_rating: Optional[int] = None, relief_rating: Optional[int] = None, closer_rating: Optional[int] = None,
|
||||
batting: Optional[int] = None, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail='You are not authorized to patch pitching cards. This event has been logged.'
|
||||
)
|
||||
|
||||
this_card = PitchingCard.get_or_none(PitchingCard.id == card_id)
|
||||
if this_card is None:
|
||||
db.close()
|
||||
raise HTTPException(status_code=404, detail=f'PitchingCard id {card_id} not found')
|
||||
|
||||
if balk is not None:
|
||||
this_card.balk = balk
|
||||
if wild_pitch is not None:
|
||||
this_card.wild_pitch = wild_pitch
|
||||
if hold is not None:
|
||||
this_card.hold = hold
|
||||
if starter_rating is not None:
|
||||
this_card.starter_rating = starter_rating
|
||||
if relief_rating is not None:
|
||||
this_card.relief_rating = relief_rating
|
||||
if closer_rating is not None:
|
||||
this_card.closer_rating = closer_rating
|
||||
if batting is not None:
|
||||
this_card.batting = batting
|
||||
|
||||
if this_card.save() == 1:
|
||||
return_val = model_to_dict(this_card)
|
||||
db.close()
|
||||
return return_val
|
||||
else:
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=418,
|
||||
detail='Well slap my ass and call me a teapot; I could not save that card'
|
||||
)
|
||||
|
||||
|
||||
@router.delete('/{card_id}')
|
||||
async def delete_card(card_id: int, token: str = Depends(oauth2_scheme)):
|
||||
if not valid_token(token):
|
||||
logging.warning(f'Bad Token: {token}')
|
||||
db.close()
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
detail='You are not authorized to patch batting cards. This event has been logged.'
|
||||
)
|
||||
|
||||
this_card = PitchingCard.get_or_none(PitchingCard.id == card_id)
|
||||
if this_card is None:
|
||||
db.close()
|
||||
raise HTTPException(status_code=404, detail=f'BattingCard id {card_id} not found')
|
||||
|
||||
count = this_card.delete_instance()
|
||||
db.close()
|
||||
|
||||
if count == 1:
|
||||
return f'Card {this_card} has been deleted'
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail=f'Card {this_card} could not be deleted')
|
||||
Loading…
Reference in New Issue
Block a user